This is a Rust to Nim comparison, similar to the Crystal to Rust post below.
Here are a few observations.
1. Going from Rust to Nim was a straightforward translation, mainly in semantics.
2. Rust is faster doing the number<->string conversion version, but Nim is faster creating palindromes numerically.
3. Nim's raw and stripped executables are significantly smaller.
4. For Nim, sometimes using slice gapfuls[0..kep-1] is faster than the array gapfuls.
5. Conclusion: For this specific task, it's a split decision on speed. If program size is a priority (embedded system, etc) Nim wins. Rust carries a larger runtime, but that's nothing new.
The system spec for all cases are (Nim compiled using gcc and clang):
System: I7-6700HQ, 3.5 GHz, Linux Kernel 5.9.10, GCC 10.2.0, LLVM 10.0.1
Rust 1.4.8, Nim 1.4.0
Compile: $ nim c --cc:[gcc|clang] --d:danger palindromicgapfuls.nim
Compile: $ rustc -C opt-level=3 -C target-cpu=native -C codegen-units=1 -C lto palindromicgapfuls.rs
Run as: $ ./palindromicgapfuls
Palindromes created using number<->string conversions
____________| speed | exe (raw) bytes | exe (stripped) bytes
rust | 19.973s | 1,373,528 | 268,576
nim (gcc) | 25.326s | 113,776 | 92,504
nim (clang) | 26.484s | 89,480 | 67,592
Palindromes created directly numerically
____________| speed | exe (raw) bytes | exe (stripped) bytes
rust | 8.769s | 1,368,352 | 268,576
nim (gcc) | 8.309s | 91,856 | 72,024
nim (clang) | 8.446s | 83,896 | 63,856
Here's the Nim code.
import strutils, typetraits # for number input
import times # for timing code execution
import unicode # for reversed
proc palindromicgapfuls(digit, count, keep: int): seq[uint64] =
var skipped = 0 # initial count of skipped values
let to_skip = count - keep # count of unwanted values to skip
var gapfuls = newSeq[uint64]() # array of palindromic gapfuls
let nn = digit * 11 # digit gapful divisor: 11, 22,...88, 99
var (power, base, basep) = (1, 1, 0)
while true:
if (power.inc; power and 1) == 0: base = base * 10
var base11 = base * 11 # value of middle two digits positions: 110..
var this_lo = base * digit # starting half for this digit: 10.. to 90..
var next_lo = base * (digit + 1) # starting half for next digit: 20.. to 100..
while this_lo < next_lo - 1:
var (palindrome, palindrome_base, left_half) = (0'u64, 0'u64, this_lo.intToStr)
let right_half = left_half.reversed
if (power and 1) == 1: basep = base11; palindrome_base = (left_half & right_half).parseUInt
else: basep = base; left_half.removeSuffix("0"); palindrome_base = (left_half & right_half).parseUInt
#else: basep = base; palindrome_base = ((left_half.removeSuffix("0"); left_half) & right_half).parseUInt
for i in 0..9:
palindrome = palindrome_base + (basep * i).uint
if (palindrome mod nn.uint) == 0:
if skipped < to_skip: (skipped += 1; continue)
gapfuls.add(palindrome)
if gapfuls.len == keep: return gapfuls
this_lo += 10
import times
proc make_palindrome(front_half: uint64, power: int): uint64 =
var (result, front_half) = (front_half, front_half)
if (power and 1) == 0: result = result div 10
while front_half > 0:
result = result * 10
result += front_half mod 10
front_half = front_half div 10
result
proc palindromicgapfuls(digit, count, keep: int): seq[uint64] =
var skipped = 0 # initial count of skipped values
let to_skip = count - keep # count of unwanted values to skip
var gapfuls = newSeq[uint64]() # array of palindromic gapfuls
let nn = uint64(digit * 11) # digit gapful divisor: 11, 22,...88, 99
var (power, base) = (1, 1)
while true:
if (power.inc; power and 1) == 0: base = base * 10
var base11 = base * 11 # value of middle two digits positions: 110..
var this_lo = base * digit # starting half for this digit: 10.. to 90..
var next_lo = base * (digit + 1) # starting half for next digit: 20.. to 100..
while this_lo < next_lo - 1:
let basep = if (power and 1) == 1: base11 else: base
var palindrome = make_palindrome(this_lo.uint64, power)
for _ in 0..9:
if palindrome mod nn == 0: (skipped.inc; if skipped > to_skip: gapfuls.add(palindrome))
palindrome += basep.uint64
if gapfuls.len >= keep: return gapfuls[0..keep-1]
this_lo += 10
Here is the common output code.
let start = epochTime()
var (count, keep) = (20, 20)
echo("First 20 palindromic gapful numbers ending with:")
for digit in 1..9: echo(digit, " : ", palindromicgapfuls(digit, count, keep) )
(count, keep) = (100, 15)
echo("\nLast 15 of first 100 palindromic gapful numbers ending in:")
for digit in 1..9: echo(digit, " : ", palindromicgapfuls(digit, count, keep) )
(count, keep) = (1_000, 10)
echo("\nLast 10 of first 1000 palindromic gapful numbers ending in:")
for digit in 1..9: echo(digit, " : ", palindromicgapfuls(digit, count, keep) )
(count, keep) = (100_000, 1)
echo("\n100,000th palindromic gapful number ending with:")
for digit in 1..9: echo(digit, " : ", palindromicgapfuls(digit, count, keep) )
(count, keep) = (1_000_000, 1)
echo("\n1,000,000th palindromic gapful number ending with:")
for digit in 1..9: echo(digit, " : ", palindromicgapfuls(digit, count, keep) )
(count, keep) = (10_000_000, 1)
echo("\n10,000,000th palindromic gapful number ending with:")
for digit in 1..9: echo(digit, " : ", palindromicgapfuls(digit, count, keep) )
echo (epochTime() - start)
Nim Rosetta Code
https://rosettacode.org/wiki/Palindromic_gapful_numbers#Nim
Rust Rosetta Code