Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. What's y'all's favorite way of dealing with floating point precision?

What's y'all's favorite way of dealing with floating point precision?

Scheduled Pinned Locked Moved The Lounge
questionjavascriptcareer
67 Posts 25 Posters 10 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Jeremy Falcon

    Not sure if this counts as a programming question, since I'm not asking for code but rather preference. I'm in a project that requires complete accuracy on numbers. So, given the following... We all know the famous of examples of stuff like this:

    0.1 + 0.2 // 0.30000000000000004

    Up until now, I've been content with rounding off any operations after the fact and calling it a day, as close enough was good enough. For applications, say that deal with currency, the age old trick is to just use integers based on a cent value. So, a `$1.23` would be stored as `123` in a variable. Sweet, but, consider this:

    // $123.45 / $2.25
    12345 / 225 // 54.86666666666667

    If I move along powers of the base, I never run into issues. But for your typical run of the mill calculations, even with integers, you still have to deal with fractional floating points in the arithmetic. So, I've been using integers _and_ rounding off any calculations to their nearest integer value. Maybe sometimes I'll `floor` or `ceil` depending on context, but that's been my current solution, which is a lot more accurate but not 100% accurate. But, good enough-ish. Soooo.... 1) You guys prefer using a library to handle stuff like this? IMO I don't use one for arithmetic because most libraries for this (at least in JavaScript) are clunky and slow and don't really do a better job anyway. 2) You think integers and rounding is also the way to go? Keeps crap simple and all that, despite needing to remember to always round after division calculations or calculations against fractional types. 3) Never do arithmetic? Tell the user to go home.

    Jeremy Falcon

    S Offline
    S Offline
    Stacy Dudovitz
    wrote on last edited by
    #56

    After decades of writing software for industrial, medical, financial and LoB (Line of Business) applications, I found that the following guidelines work: 1) Financial and money, I always use the decimal type for currency, and the smallest sized type that affords me the precision I need. So why would I use any other type in a currency/money app? Simple example: I'm writing a trading application, where the strike price will be stored in a decimal type, and the number of shares will be store in a float type. Why not use a decimal type for the number of shares? Because there's no guarantee that it will be 3 places to the right of the decimal (that's typical, but not a hard fast rule). I chose float because its the smallest type that offers the precision I seek. By smallest I mean that a double is typically twice the size of a float. For those that are tempted to respond that floats are 64 bits, and doubles are 128 bit, not necessarily. That's a very PC centric view. Note: These guidelines typically, but not always, apply to LoB 2) For medical and industrial, which usually require floating point precision to store values that may not be the same as the formatting to the display, I use floats and doubles, using the smallest type that affords the precision required by the application under development. What do I mean by the smallest type and precision? The size of the type refers to how large does the floating point type have to be in order to maintain the level of precision (the number of places after the decimal point) while not losing appreciable loss to rounding and implicit conversions (more on that below). Caveats: There are several other considerations when choosing and writing floating point code. A) Rounding loss: This refers to how precise a resulting value is after some operation is performed on it. This is not limited to mathematical operations only (multiplication, division), this also applies to any library calls used to generate a new value e.g. sqrt(...). B) Conversions: Be very very careful about mixing types i.e. decimal, float and double. When a smaller type is promoted to a larger type, it may introduce random "precision" that actually makes the new value deviate farther from the mean i.e. the new value strays farther from representing the true value. So for example:

    float pi = 3.1415927;
    float radius = 5.2;
    double circumference = 2.0f

    J 1 Reply Last reply
    0
    • S Stacy Dudovitz

      After decades of writing software for industrial, medical, financial and LoB (Line of Business) applications, I found that the following guidelines work: 1) Financial and money, I always use the decimal type for currency, and the smallest sized type that affords me the precision I need. So why would I use any other type in a currency/money app? Simple example: I'm writing a trading application, where the strike price will be stored in a decimal type, and the number of shares will be store in a float type. Why not use a decimal type for the number of shares? Because there's no guarantee that it will be 3 places to the right of the decimal (that's typical, but not a hard fast rule). I chose float because its the smallest type that offers the precision I seek. By smallest I mean that a double is typically twice the size of a float. For those that are tempted to respond that floats are 64 bits, and doubles are 128 bit, not necessarily. That's a very PC centric view. Note: These guidelines typically, but not always, apply to LoB 2) For medical and industrial, which usually require floating point precision to store values that may not be the same as the formatting to the display, I use floats and doubles, using the smallest type that affords the precision required by the application under development. What do I mean by the smallest type and precision? The size of the type refers to how large does the floating point type have to be in order to maintain the level of precision (the number of places after the decimal point) while not losing appreciable loss to rounding and implicit conversions (more on that below). Caveats: There are several other considerations when choosing and writing floating point code. A) Rounding loss: This refers to how precise a resulting value is after some operation is performed on it. This is not limited to mathematical operations only (multiplication, division), this also applies to any library calls used to generate a new value e.g. sqrt(...). B) Conversions: Be very very careful about mixing types i.e. decimal, float and double. When a smaller type is promoted to a larger type, it may introduce random "precision" that actually makes the new value deviate farther from the mean i.e. the new value strays farther from representing the true value. So for example:

      float pi = 3.1415927;
      float radius = 5.2;
      double circumference = 2.0f

      J Offline
      J Offline
      Jeremy Falcon
      wrote on last edited by
      #57

      Thanks for the reply Stacy. These are all great points. For this project, I'm in JavaScript/TypeScript and dealing with money. So there is no decimal type. But, after this chat I decided to just add two extra decimal places of resolution. So, I'll store a currency amount as 1.1234 and only round it off to 2 during reporting.

      Stacy Dudovitz wrote:

      Conversions: Be very very careful about mixing types i.e. decimal, float and double.

      Tru dat. Not sure about C#, but in JavaScript/TypeScript I only have one level of precision from a data type. As a bonus though, there is a cool way to help to avoid mixing faux types.

      // the TYPE member is not used, only to flag a delta
      export type Distinct = T & {
      __TYPE__: DistinctName
      };

      // you cannot mix these two without explicit conversion
      export type NumericTypeOne = Distinct;
      export type NumericTypeTwo = Distinct;

      Stacy Dudovitz wrote:

      Implicit Operators in C#: How To Simplify Type Conversions

      If I'm ever in C/C++ land again I'll check it out. Thanks.

      Jeremy Falcon

      S 1 Reply Last reply
      0
      • J Jeremy Falcon

        Rounding with every calculation is what I was doing. I decided to move to just using integers and cents. That's for the reply though.

        Jeremy Falcon

        R Offline
        R Offline
        realJSOP
        wrote on last edited by
        #58

        If you're using c# you can use decimal types and cast if/when you need to go back to floats/doubles.

        ".45 ACP - because shooting twice is just silly" - JSOP, 2010
        -----
        You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
        -----
        When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013

        J 1 Reply Last reply
        0
        • J Jeremy Falcon

          Thanks for the reply Stacy. These are all great points. For this project, I'm in JavaScript/TypeScript and dealing with money. So there is no decimal type. But, after this chat I decided to just add two extra decimal places of resolution. So, I'll store a currency amount as 1.1234 and only round it off to 2 during reporting.

          Stacy Dudovitz wrote:

          Conversions: Be very very careful about mixing types i.e. decimal, float and double.

          Tru dat. Not sure about C#, but in JavaScript/TypeScript I only have one level of precision from a data type. As a bonus though, there is a cool way to help to avoid mixing faux types.

          // the TYPE member is not used, only to flag a delta
          export type Distinct = T & {
          __TYPE__: DistinctName
          };

          // you cannot mix these two without explicit conversion
          export type NumericTypeOne = Distinct;
          export type NumericTypeTwo = Distinct;

          Stacy Dudovitz wrote:

          Implicit Operators in C#: How To Simplify Type Conversions

          If I'm ever in C/C++ land again I'll check it out. Thanks.

          Jeremy Falcon

          S Offline
          S Offline
          Stacy Dudovitz
          wrote on last edited by
          #59

          I was a bit alarmed :omg: by your reply and solution below: For this project, I'm in JavaScript/TypeScript and dealing with money. So there is no decimal type. But, after this chat I decided to just add two extra decimal places of resolution. So, I'll store a currency amount as 1.1234 and only round it off to 2 during reporting. There are two possible solutions: 1) If you are always/only going to traffic in money, a more robust solution would be to use integer math and display formatting. As an example, the value '$1.23" would be stored in an integer of sufficient size to house the min/max dollar value you wish to traffic in. Using RegEx, it would be trivial to strip off the '$' and '.', yielding a value of the price offset by a factor of 100. To display, you could use simple formatting. You can store the values as-is to a data store, or, if you require marshaling of values, divide the value by 100 by first casting the value to float and dividing by 100f. In this case, I would use Number or BigInt. A quick search on the largest integer type gives the following results: The biggest integer type in JavaScript is BigInt. It was introduced in ECMAScript 2020. BigInts can store integers of any size, while the Number type can only store integers between -(2^53 - 1) and 2^53 - 1. 2) You could incorporate decimal.js into your project, which will provide you with the decimal type you seek. You can find that here: https://mikemcl.github.io/decimal.js/#:~:text=decimal.-,js,available in the console now. Whichever way you choose, I would implore you NOT to add arbitrary/additional numbers to the right of the decimal place. It will come back to bite you! :((

          J 1 Reply Last reply
          0
          • J Jeremy Falcon

            Thanks for the link. My only concern with doing stuff like that, is if I start using arrays to store the fractional parts, this app is gonna slow down. Keep in mind, for this app it'll need to do thousands (potentially) of calculations per second. I may just have to settle for close enough, for this specific app.

            Jeremy Falcon

            A Offline
            A Offline
            Andre_Prellwitz
            wrote on last edited by
            #60

            Thousands of calculations per second still shouldn't take any time. Come back when you're talking billions and we can start to use SIMD or even WebGPU to do some heavy lifting. Meanwhile you need to ask stakeholders when the rounding may happen. It's pretty standard that individual transactions have tax rounded, for example, and it must stay consistent. There are multiple strategies for rounding, including even or odd rounding, and it shouldn't be chosen at random. Don't forgo correctness because of some desire for speed that's ill-placed.

            J 1 Reply Last reply
            0
            • J Jeremy Falcon

              Matt Bond wrote:

              When seeking consistency, I would wrap all of that in a utility class. This way I know it's consistent and works the same everywhere. If I need something a little different, then I either overload or add a default parameter as the occasion requires.

              Ultimately, that's what I did. Except they were utility functions because I'm more functional than oop. Same concept though.

              Matt Bond wrote:

              I agree that storing the numerator and denominator would be the best way to prevent most headaches. In C#, I would use a Fraction struct for this (home grown if one doesn't exist already). Only collapse the fraction to a primitive type as necessary. This also has the benefit of letting you use money with a decimal value, so you don't have to do the extra math to get the cents back.

              Yeah, it's an awesome idea. A pretty cool piece of code was posted earlier for rational numbers. My only concern with a language like JavaScript is the speed of that. In something like C/C++ I wouldn't think twice about using it.

              Matt Bond wrote:

              Speaking of money, you only have to store 4 decimals with money to be accurate for accounting purposes.

              Whoops. I was storing 2. Thanks for this. :laugh:

              Matt Bond wrote:

              However, we don't do multiplication and division on the money.

              How do you do arithmetic on it then? Like, to calculate interest then? Thanks for the reply btw.

              Jeremy Falcon

              M Offline
              M Offline
              Matt Bond
              wrote on last edited by
              #61

              The program deals with escrow accounts for settlement of a house sale. We just have to track incoming and outgoing money to make sure 1) each sale balances, 2) everyone gets paid the right amount, and 3) the entire bank statement balances. Thus, no multiplication nor division. For a different part of the program, we do calculate per diem and monthly payments from an interest rate. The interest rate goes out to 6 decimal points, just in case (normally only 3 are used because they are multiples of 1/8 or .125 in the USA). The math is straight multiplication, then rounds to 2 decimals using 4 down/5 up rounding. We round at this point because this result is displayed to the user and summed with other amounts for a grand total. If we stored to 4 decimals, then we could have rounding errors appear in the grand total.

              Bond Keep all things as simple as possible, but no simpler. -said someone, somewhere

              J 1 Reply Last reply
              0
              • J Jeremy Falcon

                Not sure if this counts as a programming question, since I'm not asking for code but rather preference. I'm in a project that requires complete accuracy on numbers. So, given the following... We all know the famous of examples of stuff like this:

                0.1 + 0.2 // 0.30000000000000004

                Up until now, I've been content with rounding off any operations after the fact and calling it a day, as close enough was good enough. For applications, say that deal with currency, the age old trick is to just use integers based on a cent value. So, a `$1.23` would be stored as `123` in a variable. Sweet, but, consider this:

                // $123.45 / $2.25
                12345 / 225 // 54.86666666666667

                If I move along powers of the base, I never run into issues. But for your typical run of the mill calculations, even with integers, you still have to deal with fractional floating points in the arithmetic. So, I've been using integers _and_ rounding off any calculations to their nearest integer value. Maybe sometimes I'll `floor` or `ceil` depending on context, but that's been my current solution, which is a lot more accurate but not 100% accurate. But, good enough-ish. Soooo.... 1) You guys prefer using a library to handle stuff like this? IMO I don't use one for arithmetic because most libraries for this (at least in JavaScript) are clunky and slow and don't really do a better job anyway. 2) You think integers and rounding is also the way to go? Keeps crap simple and all that, despite needing to remember to always round after division calculations or calculations against fractional types. 3) Never do arithmetic? Tell the user to go home.

                Jeremy Falcon

                M Offline
                M Offline
                mdblack98
                wrote on last edited by
                #62

                Maybe you want a currency library? You can control the rounding too with this. currency.js[^]

                1 Reply Last reply
                0
                • M Matt Bond

                  The program deals with escrow accounts for settlement of a house sale. We just have to track incoming and outgoing money to make sure 1) each sale balances, 2) everyone gets paid the right amount, and 3) the entire bank statement balances. Thus, no multiplication nor division. For a different part of the program, we do calculate per diem and monthly payments from an interest rate. The interest rate goes out to 6 decimal points, just in case (normally only 3 are used because they are multiples of 1/8 or .125 in the USA). The math is straight multiplication, then rounds to 2 decimals using 4 down/5 up rounding. We round at this point because this result is displayed to the user and summed with other amounts for a grand total. If we stored to 4 decimals, then we could have rounding errors appear in the grand total.

                  Bond Keep all things as simple as possible, but no simpler. -said someone, somewhere

                  J Offline
                  J Offline
                  Jeremy Falcon
                  wrote on last edited by
                  #63

                  Thanks for the reply man. It was helpful.

                  Jeremy Falcon

                  1 Reply Last reply
                  0
                  • A Andre_Prellwitz

                    Thousands of calculations per second still shouldn't take any time. Come back when you're talking billions and we can start to use SIMD or even WebGPU to do some heavy lifting. Meanwhile you need to ask stakeholders when the rounding may happen. It's pretty standard that individual transactions have tax rounded, for example, and it must stay consistent. There are multiple strategies for rounding, including even or odd rounding, and it shouldn't be chosen at random. Don't forgo correctness because of some desire for speed that's ill-placed.

                    J Offline
                    J Offline
                    Jeremy Falcon
                    wrote on last edited by
                    #64

                    If I needed millions, I'd be using C or Rust. But point taken...

                    Jeremy Falcon

                    1 Reply Last reply
                    0
                    • S Stacy Dudovitz

                      I was a bit alarmed :omg: by your reply and solution below: For this project, I'm in JavaScript/TypeScript and dealing with money. So there is no decimal type. But, after this chat I decided to just add two extra decimal places of resolution. So, I'll store a currency amount as 1.1234 and only round it off to 2 during reporting. There are two possible solutions: 1) If you are always/only going to traffic in money, a more robust solution would be to use integer math and display formatting. As an example, the value '$1.23" would be stored in an integer of sufficient size to house the min/max dollar value you wish to traffic in. Using RegEx, it would be trivial to strip off the '$' and '.', yielding a value of the price offset by a factor of 100. To display, you could use simple formatting. You can store the values as-is to a data store, or, if you require marshaling of values, divide the value by 100 by first casting the value to float and dividing by 100f. In this case, I would use Number or BigInt. A quick search on the largest integer type gives the following results: The biggest integer type in JavaScript is BigInt. It was introduced in ECMAScript 2020. BigInts can store integers of any size, while the Number type can only store integers between -(2^53 - 1) and 2^53 - 1. 2) You could incorporate decimal.js into your project, which will provide you with the decimal type you seek. You can find that here: https://mikemcl.github.io/decimal.js/#:~:text=decimal.-,js,available in the console now. Whichever way you choose, I would implore you NOT to add arbitrary/additional numbers to the right of the decimal place. It will come back to bite you! :((

                      J Offline
                      J Offline
                      Jeremy Falcon
                      wrote on last edited by
                      #65

                      I started with integer math. Moved away from it after finding out that doing to 4 places makes it match up well enough. About the library, decimal.js, it's too bloated for my needs (fast calculations) and doesn't really offer anything that I didn't have when I just was rounding everything.

                      Jeremy Falcon

                      1 Reply Last reply
                      0
                      • R realJSOP

                        If you're using c# you can use decimal types and cast if/when you need to go back to floats/doubles.

                        ".45 ACP - because shooting twice is just silly" - JSOP, 2010
                        -----
                        You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
                        -----
                        When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013

                        J Offline
                        J Offline
                        Jeremy Falcon
                        wrote on last edited by
                        #66

                        I'm not, but yeah that's actually a great feature of C#. Turns out COBOL has that type too, found that one out. :laugh:

                        Jeremy Falcon

                        1 Reply Last reply
                        0
                        • J Jeremy Falcon

                          Thanks for this. I should probably say, for my use case in particular, I'm in a Node project. But, it's cool to know this libs exist. Granted, I could make a C/C++ module and use that within Node, but for this project at least I'm trying to keep it zippy since JavaScript isn't as fast as C/C++.

                          Jeremy Falcon

                          C Offline
                          C Offline
                          charlieg
                          wrote on last edited by
                          #67

                          And you accuse me of overthinking it :)

                          Charlie Gilley “They who can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety.” BF, 1759 Has never been more appropriate.

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups