ruby/ruby
Numerics
Ruby's numeric tower: Numeric → Integer → Fixnum/Bignum, Float, Rational, Complex. Each has its own C file plus tightly-integrated arithmetic in numeric.c.
Files
| File | Purpose |
|---|---|
numeric.c |
Numeric, Float, Integer (Fixnum half), shared arithmetic. ~171 KB. |
numeric.rb |
A few Numeric methods in Ruby. |
bignum.c |
The arbitrary-precision integer (Bignum) implementation. ~193 KB. |
rational.c |
Exact-fraction Rational and the GCD machinery. ~70 KB. |
complex.c |
Complex numbers. ~76 KB. |
math.c |
The Math module — sin, cos, log, sqrt. |
random.c |
The Random class and Kernel#rand. ~52 KB. |
siphash.c / siphash.h |
SipHash for non-cryptographic hashing in Hash. |
Integer
Integer covers two distinct internal types unified at the language level:
Fixnum
A small integer encoded directly in the VALUE bits:
| 63 ... 2 | 1 | 0 |
| <signed integer> | x | 1 |The low bit is set (so it's distinguishable from heap pointers, which are aligned to at least 4 bytes). This gives 63-bit signed integers on 64-bit systems, 31-bit on 32-bit systems. Operations are direct CPU integer operations with overflow checks.
numeric.c::fix_plus, fix_minus, fix_mul etc. are the per-operation handlers. The compiler emits opt_plus/opt_minus/etc. to bypass full method dispatch when both operands are Fixnum.
Bignum
When a Fixnum operation overflows, the result is promoted to a Bignum:
struct RBignum {
struct RBasic basic;
long len;
BDIGIT *digits; /* sign + magnitude in BDIGIT-sized limbs */
};bignum.c implements arbitrary-precision arithmetic — addition, subtraction, multiplication (Karatsuba above a threshold), division, modulo, GCD, modular exponentiation. The implementation is hand-tuned C and competes with libraries like GMP for the operations Ruby cares about.
Bignums are silently promoted to Fixnums when they shrink to fit; the VM never exposes the distinction to user code.
Float
Float is IEEE 754 double-precision (64-bit). On most platforms, a Float is a heap object:
struct RFloat {
struct RBasic basic;
double float_value;
};On platforms with the Flonum optimisation (most 64-bit platforms), Floats are encoded directly in the VALUE bits — no heap allocation:
| 63 ... 2 | 1 | 0 |
| <packed double> | 0 | 1 | 0 |The Flonum encoding reuses 62 bits of the double's representation, sacrificing a bit of mantissa precision. RB_FLONUM_P(v) tests for it. Most numeric code is Flonum-aware via macros that pack/unpack.
Float arithmetic in Ruby goes through the standard IEEE 754 ops via numeric.c::flo_plus, flo_lt, etc. Special values: Float::INFINITY, Float::NAN, Float::MAX, Float::EPSILON.
Rational
A fraction of two integers (numerator / denominator), kept in lowest terms:
struct RRational {
struct RBasic basic;
VALUE num; /* an Integer */
VALUE den; /* a positive Integer */
};rational.c::r_gcd computes GCD via the Euclidean algorithm. Construction (Rational(a, b)) reduces immediately.
Arithmetic on Rationals stays exact: Rational(1, 3) + Rational(1, 6) == Rational(1, 2). Mixed Rational/Integer arithmetic stays Rational; Rational/Float promotes to Float (at the cost of precision).
The literal syntax 1r produces Rational(1, 1).
Complex
struct RComplex {
struct RBasic basic;
VALUE real;
VALUE imag;
};Complex(a, b) = a + bi. The fields can be any Numeric — Integer, Float, or even Rational. complex.c defines the arithmetic in the obvious way.
The literal syntax 1+2i is Complex(1, 2).
Math module
math.c defines Math.sin, Math.cos, Math.log, Math.sqrt, Math.atan2, Math.hypot, etc. Each is a thin wrapper over the C standard library's math functions, with NaN/range checks.
Math::PI and Math::E are computed at boot.
For arbitrary-precision math (Bignum exponents, Rational **), the routines in bignum.c and rational.c take over.
Random
random.c implements Random — a Mersenne Twister-based PRNG:
r = Random.new(42)
r.rand # 0.0..1.0
r.rand(10) # 0..9
r.bytes(8) # 8 random bytesPer-process and per-Ractor default RNGs are seeded at startup from /dev/urandom (or the OS equivalent). Random::DEFAULT is the per-Ractor default.
SecureRandom (in lib/securerandom.rb) uses OpenSSL or getrandom(2) for cryptographic randomness.
Coercion
When an arithmetic operation receives a non-matching pair of operands, Ruby calls coerce:
1 + Rational(1, 2)
# Integer#+ doesn't know what to do with Rational
# → calls Rational#coerce(1) → returns [Rational(1), Rational(1, 2)]
# → arithmetic proceeds on the coerced pairnumeric.c::num_coerce is the universal Numeric#coerce fallback. User-defined Numeric subclasses override it.
Performance notes
- Fixnum arithmetic is constant time and inlined by the JIT. Most int-heavy hot paths stay in Fixnum.
- Bignum arithmetic scales with the number of limbs. Karatsuba kicks in around 100 limbs.
- Float arithmetic under Flonum is also inlined.
- Rational/Complex are heap objects and slower; appropriate for cases where exactness matters.
Common pitfalls
- Integer division truncates:
7 / 2 == 3. UseRational(7, 2)orFloat(7) / 2for non-truncating. 0.1 + 0.2 != 0.3: standard IEEE 754 behaviour. UseBigDecimal(inbigdecimalgem) for decimal arithmetic.Math.sqrt(-1): returns NaN, not Complex.Mathis float-only; useCMathfor Complex-aware math.Randomper-Ractor: seeded independently per Ractor; reproducible output requires explicit seeding.
Entry points for modification
- New Numeric method: add to the relevant file (
numeric.c/bignum.c/rational.c/complex.c) and register inInit_*. - Performance: profile under YJIT; coercion paths are usually the bottleneck for mixed-type arithmetic.
- New literal syntax: parser change in
parse.yandprism/, then ensure the literal lowers to the right Numeric subclass.
See systems/compiler.md for opt_plus/opt_minus opcode specialisation and systems/vm.md for Fixnum/Float fast paths.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.