Function toFloat [src]

Return a floating-point value that is the closest value to a Rational. The result may not be exact if the Rational is too precise or too large for the target type.

Prototype

pub fn toFloat(self: Rational, comptime T: type) !T

Parameters

self: RationalT: type

Source

pub fn toFloat(self: Rational, comptime T: type) !T { // Translated from golang.go/src/math/big/rat.go. // TODO: Indicate whether the result is not exact. debug.assert(@typeInfo(T) == .float); const fsize = @typeInfo(T).float.bits; const BitReprType = std.meta.Int(.unsigned, fsize); const msize = math.floatMantissaBits(T); const msize1 = msize + 1; const msize2 = msize1 + 1; const esize = math.floatExponentBits(T); const ebias = (1 << (esize - 1)) - 1; const emin = 1 - ebias; if (self.p.eqlZero()) { return 0; } // 1. left-shift a or sub so that a/b is in [1 << msize1, 1 << (msize2 + 1)] var exp = @as(isize, @intCast(self.p.bitCountTwosComp())) - @as(isize, @intCast(self.q.bitCountTwosComp())); var a2 = try self.p.clone(); defer a2.deinit(); var b2 = try self.q.clone(); defer b2.deinit(); const shift = msize2 - exp; if (shift >= 0) { try a2.shiftLeft(&a2, @as(usize, @intCast(shift))); } else { try b2.shiftLeft(&b2, @as(usize, @intCast(-shift))); } // 2. compute quotient and remainder var q = try Int.init(self.p.allocator); defer q.deinit(); // unused var r = try Int.init(self.p.allocator); defer r.deinit(); try Int.divTrunc(&q, &r, &a2, &b2); var mantissa = extractLowBits(q, BitReprType); var have_rem = r.len() > 0; // 3. q didn't fit in msize2 bits, redo division b2 << 1 if (mantissa >> msize2 == 1) { if (mantissa & 1 == 1) { have_rem = true; } mantissa >>= 1; exp += 1; } if (mantissa >> msize1 != 1) { // NOTE: This can be hit if the limb size is small (u8/16). @panic("unexpected bits in result"); } // 4. Rounding if (emin - msize <= exp and exp <= emin) { // denormal const shift1 = @as(math.Log2Int(BitReprType), @intCast(emin - (exp - 1))); const lost_bits = mantissa & ((@as(BitReprType, @intCast(1)) << shift1) - 1); have_rem = have_rem or lost_bits != 0; mantissa >>= shift1; exp = 2 - ebias; } // round q using round-half-to-even var exact = !have_rem; if (mantissa & 1 != 0) { exact = false; if (have_rem or (mantissa & 2 != 0)) { mantissa += 1; if (mantissa >= 1 << msize2) { // 11...1 => 100...0 mantissa >>= 1; exp += 1; } } } mantissa >>= 1; const f = math.scalbn(@as(T, @floatFromInt(mantissa)), @as(i32, @intCast(exp - msize1))); if (math.isInf(f)) { exact = false; } return if (self.p.isPositive()) f else -f; }