[HN Gopher] Show HN: Floating point arithmetic types in C++ for ...
___________________________________________________________________
Show HN: Floating point arithmetic types in C++ for any size and
any base
Since there is so much interest on HN in floats lately and their
software implementations, I wanted to show mine. It has no use and
is just for teaching me floats and C++. Give me your thoughts.
Author : seg_fault
Score : 45 points
Date : 2024-10-18 17:42 UTC (3 days ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| a_t48 wrote:
| Have nothing to say other than - neat!
| seg_fault wrote:
| Thank you :)
| fuhsnn wrote:
| For "any size" I was kind of expecting arbitrary sized
| mantissa/exponent, can be useful for emulating weird DACs, for
| example, 12-bit mantissa and 3-bit exponent[1].
|
| [1] https://ajxs.me/blog/Yamaha_DX7_Technical_Analysis.html
| badmintonbaseba wrote:
| Possibly could be combined with C23's _BitInt(N) for the
| template arguments? I think it's available in clang as a C++
| extension.
|
| edit: or I guess you could have your own Tmantissa and
| Texponent types as custom classes that correctly model
| _BitInt(N), they don't seem to be required to be builtin
| integral types.
| seg_fault wrote:
| Actually you can specify the numeric limits of the mantissa and
| the exponent. They can be specified as template arguments[0].
| So you could do: Float<uint8_t, // type of
| the mantissa uint8_t, // type of the exponent
| 0, // lowest possible value of the mantissa
| 4095, // highest possible value of the mantissa
| 0, // lowest possible value of the exponent
| 7> // highest possible value of the exponent
|
| The Float then simulates an unsigned 12bit mantissa and a 3bit
| exponent. Sure it still takes 16 bytes. But you could create a
| union with bitfields where you shrink that even further.
|
| [0]
| https://github.com/clemensmanert/fas/blob/58f9effbe6c13ab334...
| Archit3ch wrote:
| Can you go in the other direction? Higher exponent and
| mantissa than regular float/double?
| seg_fault wrote:
| Sure. Float<int64_t, int64_t>
|
| Gives you a signed Mantissa with 64 bit and a signed
| Exponent with 64bit. Since there are numeric limits for
| int64_t available, Float knows the max and the min value.
|
| You could get even bigger ranges for Float by implementing
| your own big integer type.
| badmintonbaseba wrote:
| Nice!
|
| > TODO: (configurable) rounding support
|
| What's the default rounding mode? Round to nearest even?
|
| You might be interested in https://www.open-
| std.org/jtc1/sc22/wg21/docs/papers/2024/p33... too, which is a
| recent paper for introducing reproducible floating point to C++.
|
| Very small floating point types can be handy for exhaustive
| testing of floating point function templates, especially ones
| that take multiple arguments. Walking over all floating point
| values for a small type often finds most if not all corner cases
| that can manifest with a floating point type of any size.
| seg_fault wrote:
| Rounding: actually it just cuts off. I have not spent much time
| to think about how to specify and implement the different
| rounding modes. Maybe some day...
|
| Thanks for the hint to the paper. I also faced these issues.
| Thus, I provided a constructor which accepts mantissa and
| exponent as values. Very handy for the unittests.
| badmintonbaseba wrote:
| By cutting off do you mean that it correctly rounds towards
| zero? Maybe you can implement rounding to closest by just
| doing the calculation in a one digit wider mantissa with
| rounding to zero and observing the last digit, at least for
| an even base. It won't be rounding to even though, but for
| that a 2 digit wider mantissa is probably enough.
|
| Rounding to nearest with an odd base doesn't seem to be as
| straightforwardly implementable from rounding to zero
| calculations at a higher precision.
| seg_fault wrote:
| I remember that I tried that some time ago. Especially the
| multiplication was tough, but I can not recall where I gave
| up. When I find some time, I will pick it up again :)
| codr7 wrote:
| Here is an example of the other end of the spectrum that I've
| used a couple of times: very simple fixpoints.
|
| https://github.com/codr7/claes/blob/main/src/claes/f64.hpp
| listeria wrote:
| Consider dropping the specializations for the type traits, given
| that it's undefined behavior:
|
| https://en.cppreference.com/w/cpp/types/is_fundamental
|
| https://en.cppreference.com/w/cpp/types/is_floating_point
|
| https://en.cppreference.com/w/cpp/types/is_arithmetic
|
| https://en.cppreference.com/w/cpp/types/is_scalar
|
| https://en.cppreference.com/w/cpp/types/is_object
| seg_fault wrote:
| I don't get what you mean. I thought they specify how the type
| can be used?
| secondcoming wrote:
| Technically, you're not supposed to add your own
| specialisations to the `std` namespace
| pmalynin wrote:
| In general this isn't true (i guess it is in this specific
| context). For example I believe it's totally expected to
| specialize std hash
| badmintonbaseba wrote:
| The cppreference page says:
|
| > If the program adds specializations for std::is_fundamental
| or std::is_fundamental_v, the behavior is undefined.
|
| This is an oversimplification. The actual rule is
| https://eel.is/c++draft/library#namespace.std-2 .
|
| > the specialization meets the standard library requirements
| for the original template.
|
| For is_fundamental<YourClassType> it means that
| is_fundamental<YourClassType>::value must be false, as
| YourClassType is not a fundamental type, as defined in
| https://eel.is/c++draft/basic.fundamental#17 .
|
| Some traits are just not designed to be customization points.
| dataflow wrote:
| Why is std::is_object even specialized here? Isn't it always
| true regardless?
| rurban wrote:
| It's copyrighted so I should not even look at it, and therefore
| not comment on it.
| skissane wrote:
| No LICENSE. Have you thought about adding one?
___________________________________________________________________
(page generated 2024-10-21 23:00 UTC)