-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
compiler_rt: Tracking Issue (Binary) Fixed-Point Fractional Routines #15678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
|
|
|
TODO
Documentation is maintained in https://github.com/matu3ba/matu3ba.github.io/tree/master/crt until review or I have a better place for it to reduce maintenance churn. |
tldr; stdfix.h looks like a semi-useless abstraction over type sizes. see https://stackoverflow.com/questions/74776106/understanding-fixed-point-notation-in-gcc-clang Unless we have very convincing use cases, which justify implementing a large subset of all the routines, I think binary fixed point routines belong into a library, which allows the user to only expose the functions needed and to do the type checks at comptime. Fixed point numbers allow accurate error estimation for arbitrary propagation (in contrast to varying exponents, see Practical float knowledge from https://blog.demofox.org/2017/11/21/floating-point-precision/), so I think Zig should offer something like this, but I have not seen use cases requiring those in libstd. |
Hi, I'm currently implementing Apache arrow in arrow-zig and the only type I'm missing is Decimal!
Can you elaborate on this? As a user it's much clearer to have language support and write: const a: d2_1 = 34.1;
const b = a + @as(d2_1, 3.2); than to have library support and write: const D2_1 = decimal_lib.Decimal(2, 1);
const a = D2_1.init(34, 1);
const b = a.plus(D2_1.init(3, 2)); |
Please have a look at the according tracking issue then: #15677.
I'll post the details in the open accessible binary fixed-point standard later today (20:40 UTC or so), from which you derive the optimal number representation in the same way for decimal (4 bit represent a digit in the unpacked version, packed one is more complex). Plus my implementation idea for binary fixed point numbers, if you want to implement+upstream the unpacked decimal ones yourself. (nothing fancy, just some comptime number crunshing) |
Free download of standard from iso website, search for "ISO/IEC TR 18037:2008". Implementation sketch //! Binary fixed point number x = s * n * (b^f)
//! s sign, n nominator, b base = 2, f implicit factor as integer value
//! In contrast to floating point numbers, fixed-point infinites or NaNs are
//! not supported.
//!
//! ISO/IEC TR 18037:2008(E)
//! typeA binary fixed-point [0,1] or [-1,1]:
//! +-.DDDDDDDD
//! ^databits => _Fract
//! radix point
//! typeB binary fixed-point [0, int.fract] or [-int.fract, int.fract]
//! +-IIIIII.FFFFFFF
//! integral^fractional => _Accum
//! radix point
//!
//! Standard provides the following suggestions:
//! - fract_leN_t, fract_leM_leN_t [most confusing not accum_leM_leN_t]
//! to denote typeA with at least N data bits or M integral bits and N fractional bits.
//! - Define macro names like SFRACT_FBIT to inform about actual precisions etc.
//! Standard recommends:
//! - Macros FX_FRACT_OVERFLOW, FX_ACCUM_OVERFLOW specify overflow behavior.
//! - FX_FULL_PRECISION specifies precision, typically this is 1ulp, but
//! integer implementations may want to trade higher error for better performance.
//! - Exception for 1 and –1 Multiplication Results for hardware acceleration:
//! The product can be saturated (to long fract format) before being added into
//! the accumulator.
//!
//! This is an initial implementation, which does not support FX_FRACT_OVERFLOW,
//! FX_ACCUM_OVERFLOW via comptime-selection and neither FX_FULL_PRECISION.
const std = @import("std");
const assert = std.debug.assert;
const testing = std.testing;
const builtin = std.builtin;
const Sign = enum {
signed,
unsigned,
};
/// Returns binary fixed point number methods including comptime-introspection.
/// TODO: hardware detection
pub fn BinaryFixPointNumber(
comptime sign: std.builtin.Signedness,
comptime nominator_bit_cnt: u16,
comptime factor: comptime_int,
) type {
// comptime assert(@TypeOf(nominator) == integer);
// comptime assert(@TypeOf(base) == integer);
// comptime assert(@TypeOf(factor) == integer);
return struct {
// TODO
// - figure out how the hw instructions on x86 work
data: std.meta.Int(sign, nominator_bit_cnt + factor),
pub fn Sign() std.builtin.Signedness {
return sign;
}
pub fn Nominator() type {
return std.meta.Int(sign, nominator_bit_cnt);
}
pub fn Factor() type {
return factor;
}
// TODO nominator_offset ?
// conversion
};
}
test "sizes typeA binary floating point number" {
const Bin0 = BinaryFixPointNumber(.signed, 1, 0);
comptime {
try testing.expect(@typeInfo(Bin0).Struct.fields[0].type == i1);
// try testing.expect(@sizeOf(@typeInfo(Bin0).Struct.fields[0].type) == 1);
}
} Addition, subtraction, multiplication etc work like twos complement with the exception that factor must be identical or we need to align/padd fixed point numbers accordingly. The main drawback of providing syntax support is that its more costly than integers and the [overflow + rounding] behavior is hidden behind macros (I do assume its the same for decimals here), so I think this does not fit into Zig's Zen. |
@matu3ba where are you getting these lists of symbols from? |
https://gcc.gnu.org/onlinedocs/gccint/Fixed-point-fractional-library-routines.html. I did add the link to the description. |
I'm not seeing the value in this tracking issue. |
Uh oh!
There was an error while loading. Please reload this page.
Note: Maximum character limit reached, so this table is split into 4 tables. List taken from https://gcc.gnu.org/onlinedocs/gccint/Fixed-point-fractional-library-routines.html.
TODO
Documentation is maintained in https://github.com/matu3ba/matu3ba.github.io/tree/master/crt until review or I have a better place for it to reduce maintenance churn.
The text was updated successfully, but these errors were encountered: