[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)