mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 22:33:08 +00:00
Most of this migration was performed automatically with `zig fmt`. There were a few exceptions which I had to manually fix: * `@alignCast` and `@addrSpaceCast` cannot be automatically rewritten * `@truncate`'s fixup is incorrect for vectors * Test cases are not formatted, and their error locations change
92 lines
2.8 KiB
Zig
92 lines
2.8 KiB
Zig
const std = @import("std");
|
|
|
|
/// A custom N-bit floating point type, representing `f * 2^e`.
|
|
/// e is biased, so it be directly shifted into the exponent bits.
|
|
/// Negative exponent indicates an invalid result.
|
|
pub fn BiasedFp(comptime T: type) type {
|
|
const MantissaT = mantissaType(T);
|
|
|
|
return struct {
|
|
const Self = @This();
|
|
|
|
/// The significant digits.
|
|
f: MantissaT,
|
|
/// The biased, binary exponent.
|
|
e: i32,
|
|
|
|
pub fn zero() Self {
|
|
return .{ .f = 0, .e = 0 };
|
|
}
|
|
|
|
pub fn zeroPow2(e: i32) Self {
|
|
return .{ .f = 0, .e = e };
|
|
}
|
|
|
|
pub fn inf(comptime FloatT: type) Self {
|
|
return .{ .f = 0, .e = (1 << std.math.floatExponentBits(FloatT)) - 1 };
|
|
}
|
|
|
|
pub fn eql(self: Self, other: Self) bool {
|
|
return self.f == other.f and self.e == other.e;
|
|
}
|
|
|
|
pub fn toFloat(self: Self, comptime FloatT: type, negative: bool) FloatT {
|
|
var word = self.f;
|
|
word |= @as(MantissaT, @intCast(self.e)) << std.math.floatMantissaBits(FloatT);
|
|
var f = floatFromUnsigned(FloatT, MantissaT, word);
|
|
if (negative) f = -f;
|
|
return f;
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn floatFromUnsigned(comptime T: type, comptime MantissaT: type, v: MantissaT) T {
|
|
return switch (T) {
|
|
f16 => @as(f16, @bitCast(@as(u16, @truncate(v)))),
|
|
f32 => @as(f32, @bitCast(@as(u32, @truncate(v)))),
|
|
f64 => @as(f64, @bitCast(@as(u64, @truncate(v)))),
|
|
f128 => @as(f128, @bitCast(v)),
|
|
else => unreachable,
|
|
};
|
|
}
|
|
|
|
/// Represents a parsed floating point value as its components.
|
|
pub fn Number(comptime T: type) type {
|
|
return struct {
|
|
exponent: i64,
|
|
mantissa: mantissaType(T),
|
|
negative: bool,
|
|
/// More than max_mantissa digits were found during parse
|
|
many_digits: bool,
|
|
/// The number was a hex-float (e.g. 0x1.234p567)
|
|
hex: bool,
|
|
};
|
|
}
|
|
|
|
/// Determine if 8 bytes are all decimal digits.
|
|
/// This does not care about the order in which the bytes were loaded.
|
|
pub fn isEightDigits(v: u64) bool {
|
|
const a = v +% 0x4646_4646_4646_4646;
|
|
const b = v -% 0x3030_3030_3030_3030;
|
|
return ((a | b) & 0x8080_8080_8080_8080) == 0;
|
|
}
|
|
|
|
pub fn isDigit(c: u8, comptime base: u8) bool {
|
|
std.debug.assert(base == 10 or base == 16);
|
|
|
|
return if (base == 10)
|
|
'0' <= c and c <= '9'
|
|
else
|
|
'0' <= c and c <= '9' or 'a' <= c and c <= 'f' or 'A' <= c and c <= 'F';
|
|
}
|
|
|
|
/// Returns the underlying storage type used for the mantissa of floating-point type.
|
|
/// The output unsigned type must have at least as many bits as the input floating-point type.
|
|
pub fn mantissaType(comptime T: type) type {
|
|
return switch (T) {
|
|
f16, f32, f64 => u64,
|
|
f128 => u128,
|
|
else => unreachable,
|
|
};
|
|
}
|