I’ve been working on a shard that is an interesting experiment. big_number is a pure Crystal implementation of arbitrary-precision BigInt, BigRational, BigFloat, and BigDecimal with No C dependencies just Crystal.
- no libgmp
- no Cross-compilation
- no static libgmp
- no alternate license
I wanted to see how far pure Crystal could go. Turns out pretty far. But not all the way in preformance.
require "big_number"
# Arbitrary-precision integers
a = BigNumber::BigInt.new("123456789012345678901234567890")
b = BigNumber::BigInt.new(42)
puts a * b
# Exact rational arithmetic
r = BigNumber::BigRational.new(1, 3) + BigNumber::BigRational.new(1, 6)
puts r # => 1/2
# Arbitrary-precision floats (configurable precision, default 128 bits)
f = BigNumber::BigFloat.new("3.14159265358979323846", precision: 256)
puts f * BigNumber::BigFloat.new(2)
# Fixed-scale decimals
d = BigNumber::BigDecimal.new("1.005") + BigNumber::BigDecimal.new("2.345")
puts d # => 3.350
Drop-in stdlib replacement
This is the part I’m most excited about. You can swap one require line and eliminate the GMP dependency entirely:
# Before:
require "big"
# After:
require "big_number/stdlib"
# Everything keeps working
x = BigInt.new("123456789" * 100)
x.is_a?(Int) # => true
42.to_big_i # => works
x.hash == BigInt.new(x.to_s).hash # => true
Performance
well it is good and is probably suitable for a lot of use cases but it does not stack up at scale. I am keeping some benchmarks in the README.md.
Anyone find this interesting
Would anyone use this for static binaries?
Is there an interest in remove c lib dependencies from the stdlib?
Anything else I missed?
5 Likes
Looks awesome!
Matching libgmp performance wouldn’t be easy though - looks like it use assembly routines for all supported platforms. But pure Crystal implementation is great for things like WASM.
yeah I dont think a project like this would ever be able to achieve the same performance. So it could not be a goal of this project.
Right now the goal of this project is to see if this is possible and if it has any use case. This is experimental in the true sense of the word. It is an experiment.
It might be able to. Crystal supports inline assembly, so this project would just need CPU-specific implementations of some operations with a generic fallback. For example, AVX512-capable CPUs might be able to parallelize some of these operations by allowing you to process 8 limbs per iteration. That won’t necessarily give you 8x performance for the entire operation, but performing 8 64-bit multiplications in a single CPU instruction might speed up BigNumber::BigInt#* for that CPU, for example.
libgmp’s had decades of tuning (I want to say I was using it in the late 90s?), so the fact that this project is even within an order of magnitude with no CPU-specific optimizations is promising if you want to continue with it.
3 Likes
That is encouraging. I am enjoying exploring this space so I am going to continue to work on this.
I really want to see what people use this for in Crystal and what their use cases are. When I search github I get mostly advent of code, experimental languages, and crypto. I imagine if I could search non public projects I would get more scientific projects which I think are the real powerhouse users.
But that is entirely guessing.
1 Like
There ain’t that many big number libraries, and an AI might just port code from GMP or another lib into Crystal without your knowledge. I’d be very wary of licensing issues (GMP is LGPL for example).
Starting a big number shard in super interesting, it would be awful to get into licensing issues.
5 Likes
This is great! “big“ appears in unexpected places sometimes; I remember writing an application that I wanted to statically link just to find out that it had a dependency on GMP because it used the “jwt“ shard. Having a pure crystal implementation with a permissive license is awesome; even if the performance is not on par with GMP, it’s still a better choice for many use cases.
1 Like
So this is actually great to hear. I am curious what pain points and use cases there are around GMP.