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;
}
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;
}
const info = FloatInfo.from(T);
var value: T = 0;
if (n.exponent <= info.max_exponent_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 {
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;
}