Currently there are no to_i128
and to_u128
methods for BigInts
.
This causes some problems for doing math in some instances.
See e.g. Integer root algorithm · Issue #13416 · crystal-lang/crystal · GitHub and
Ruby out performs Crystal significantly on this numerical algorithm - #15 by jzakiya
A really simple (and not too ugly) way to convert a number of one type to another is as follows.
If a = "1283984894429".to_big_i
can fit into a smaller Int
primitive you can do
x = typeof(1i64).new(a.to_s)
, and x = a
will now be a Int64
.
Here’s an actual use case from above issue.
lib LibGMP
fun root = __gmpz_root(rop : MPZ*, op : MPZ*, n : ULong) : Int
end
def irootgmp(val, n : Int::Primitive)
# error handling / range check not shown
root = BigInt.new { |mpz| LibGMP.root(mpz, val.to_big_i, n) }
typeof(val).new(root.to_s)
end
Here LibGMP.root(mpz, val.to_big_i, n)
returns the nth integer root of val
.
root
is returned from the function as a BigInt
, but is always smaller than val
, and when doing actual math in an algorithm you usually want them to be the same type.
So typeof(val).new(root.to_s)
returns root
as the same type as val
.
This gets around the current case where you can’t do BigInt.to_(u|i)128
.
This has the added benefit of converting any larger Int
type to a smaller one it can fit within (and obviously vice versa) without having to do explicit to_(u|i)xint
.