mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
The majority of these are in comments, some in doc comments which might affect the generated documentation, and a few in parameter names - nothing that should be breaking, however.
131 lines
5.0 KiB
Zig
131 lines
5.0 KiB
Zig
//! Representation of a float as the significant digits and exponent.
|
|
//! The fast path algorithm using machine-sized integers and floats.
|
|
//!
|
|
//! This only works if both the mantissa and the exponent can be exactly
|
|
//! represented as a machine float, since IEE-754 guarantees no rounding
|
|
//! will occur.
|
|
//!
|
|
//! There is an exception: disguised fast-path cases, where we can shift
|
|
//! powers-of-10 from the exponent to the significant digits.
|
|
|
|
const std = @import("std");
|
|
const math = std.math;
|
|
const common = @import("common.zig");
|
|
const FloatInfo = @import("FloatInfo.zig");
|
|
const Number = common.Number;
|
|
const floatFromU64 = common.floatFromU64;
|
|
|
|
fn isFastPath(comptime T: type, n: Number(T)) bool {
|
|
const info = FloatInfo.from(T);
|
|
|
|
return info.min_exponent_fast_path <= n.exponent and
|
|
n.exponent <= info.max_exponent_fast_path_disguised and
|
|
n.mantissa <= info.max_mantissa_fast_path and
|
|
!n.many_digits;
|
|
}
|
|
|
|
// upper bound for tables is floor(mantissaDigits(T) / log2(5))
|
|
// for f64 this is floor(53 / log2(5)) = 22.
|
|
//
|
|
// Must have max_disguised_fast_path - max_exponent_fast_path entries. (82 - 48 = 34 for f128)
|
|
fn fastPow10(comptime T: type, i: usize) T {
|
|
return switch (T) {
|
|
f16 => ([8]f16{
|
|
1e0, 1e1, 1e2, 1e3, 1e4, 0, 0, 0,
|
|
})[i & 7],
|
|
|
|
f32 => ([16]f32{
|
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
|
|
1e8, 1e9, 1e10, 0, 0, 0, 0, 0,
|
|
})[i & 15],
|
|
|
|
f64 => ([32]f64{
|
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
|
|
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
|
|
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
})[i & 31],
|
|
|
|
f128 => ([64]f128{
|
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
|
|
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
|
|
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23,
|
|
1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31,
|
|
1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
|
|
1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47,
|
|
1e48, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
})[i & 63],
|
|
|
|
else => unreachable,
|
|
};
|
|
}
|
|
|
|
fn fastIntPow10(comptime T: type, i: usize) T {
|
|
return switch (T) {
|
|
u64 => ([16]u64{
|
|
1, 10, 100, 1000,
|
|
10000, 100000, 1000000, 10000000,
|
|
100000000, 1000000000, 10000000000, 100000000000,
|
|
1000000000000, 10000000000000, 100000000000000, 1000000000000000,
|
|
})[i],
|
|
|
|
u128 => ([35]u128{
|
|
1, 10,
|
|
100, 1000,
|
|
10000, 100000,
|
|
1000000, 10000000,
|
|
100000000, 1000000000,
|
|
10000000000, 100000000000,
|
|
1000000000000, 10000000000000,
|
|
100000000000000, 1000000000000000,
|
|
10000000000000000, 100000000000000000,
|
|
1000000000000000000, 10000000000000000000,
|
|
100000000000000000000, 1000000000000000000000,
|
|
10000000000000000000000, 100000000000000000000000,
|
|
1000000000000000000000000, 10000000000000000000000000,
|
|
100000000000000000000000000, 1000000000000000000000000000,
|
|
10000000000000000000000000000, 100000000000000000000000000000,
|
|
1000000000000000000000000000000, 10000000000000000000000000000000,
|
|
100000000000000000000000000000000, 1000000000000000000000000000000000,
|
|
10000000000000000000000000000000000,
|
|
})[i],
|
|
|
|
else => unreachable,
|
|
};
|
|
}
|
|
|
|
pub fn convertFast(comptime T: type, n: Number(T)) ?T {
|
|
const MantissaT = common.mantissaType(T);
|
|
|
|
if (!isFastPath(T, n)) {
|
|
return null;
|
|
}
|
|
|
|
// TODO: x86 (no SSE/SSE2) requires x87 FPU to be setup correctly with fldcw
|
|
const info = FloatInfo.from(T);
|
|
|
|
var value: T = 0;
|
|
if (n.exponent <= info.max_exponent_fast_path) {
|
|
// normal fast path
|
|
value = @intToFloat(T, n.mantissa);
|
|
value = if (n.exponent < 0)
|
|
value / fastPow10(T, @intCast(usize, -n.exponent))
|
|
else
|
|
value * fastPow10(T, @intCast(usize, n.exponent));
|
|
} else {
|
|
// disguised fast path
|
|
const shift = n.exponent - info.max_exponent_fast_path;
|
|
const mantissa = math.mul(MantissaT, n.mantissa, fastIntPow10(MantissaT, @intCast(usize, shift))) catch return null;
|
|
if (mantissa > info.max_mantissa_fast_path) {
|
|
return null;
|
|
}
|
|
value = @intToFloat(T, mantissa) * fastPow10(T, info.max_exponent_fast_path);
|
|
}
|
|
|
|
if (n.negative) {
|
|
value = -value;
|
|
}
|
|
return value;
|
|
}
|