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. How hard would it be to have a Rational Number type, so that there would never be floating point errors?

How hard would it be to have a Rational Number type, so that there would never be floating point errors?

Scheduled Pinned Locked Moved The Lounge
c++question
33 Posts 19 Posters 0 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.
  • OriginalGriffO OriginalGriff

    And storage of Pi would be?

    Sent from my Amstrad PC 1640 Bad command or file name. Bad, bad command! Sit! Stay! Staaaay... AntiTwitter: @DalekDave is now a follower!

    S Offline
    S Offline
    swampwiz
    wrote on last edited by
    #15

    I suppose that there could be some setting in this RationalNumber class that would allow for infinite computation for numbers like pi & e, if the client so desired. Pi could use Chudnovsky algorithm. e would be pretty straightforward too. And here's a quickie: 1833616417 / 583658233

    K 1 Reply Last reply
    0
    • S swampwiz

      It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

      S Offline
      S Offline
      Super Lloyd
      wrote on last edited by
      #16

      Well... you will quickly get overflow after some simple operations ( + - * / )... Not to mention some number can't be approximated by rational number. A large infinity of them!

      A new .NET Serializer All in one Menu-Ribbon Bar Taking over the world since 1371!

      1 Reply Last reply
      0
      • OriginalGriffO OriginalGriff

        And storage of Pi would be?

        Sent from my Amstrad PC 1640 Bad command or file name. Bad, bad command! Sit! Stay! Staaaay... AntiTwitter: @DalekDave is now a follower!

        C Offline
        C Offline
        CPallini
        wrote on last edited by
        #17

        Don't be irrational, π would be automatically promoted to 'floating point error'.

        1 Reply Last reply
        0
        • S swampwiz

          It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

          J Offline
          J Offline
          John Stewien
          wrote on last edited by
          #18

          You mean like this BigRational class in C# [SwordfishCollections/BigRational.cs at master · stewienj/SwordfishCollections · GitHub](https://github.com/stewienj/SwordfishCollections/blob/master/Swordfish.NET/General/BigRational.cs)

          1 Reply Last reply
          0
          • S swampwiz

            It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

            G Offline
            G Offline
            gdemont
            wrote on last edited by
            #19

            Already done : check Rationals @ http://mathpaqs.sourceforge.net/. It's even generic, so you can use whatever type for a,b in the fractions a/b: integers, big integers, polynomials, ...

            K S 2 Replies Last reply
            0
            • S swampwiz

              I suppose that there could be some setting in this RationalNumber class that would allow for infinite computation for numbers like pi & e, if the client so desired. Pi could use Chudnovsky algorithm. e would be pretty straightforward too. And here's a quickie: 1833616417 / 583658233

              K Offline
              K Offline
              kalberts
              wrote on last edited by
              #20

              That wouldn't make pi a rational number, though. It would be misleading to provide pi in a class named something like rational_number - unless you called it not pi, but pi_approximated_as_a_rational_number. A (true) story about pi, I believe it is from around 1980 - I was told the story around 1983 by a guy who had participated in the hunt for The True pi: At Bergen University, Norway, one professor teaching numerical methods and error propagation had his students estimate the error expected in some trancendental functions in difficult number ranges, and verify it on the University's new shining IBM 3080 mainframe. The students came back and reported significantly larger errors than their estimates suggested. The surprised professor set out to find the cause of this. It turned out that the IBM 3080 Fortran libraries were carbon copies of the 370 libraries. Which were carbon copies of 360 libraries. The 360 got its libraries (in assembler format, of course, with floating point constants in hexadecimal format) as an adaptation of the old 7090 libraries - machines with a different instruction set and 36 bit word length (rather the 360's 32 bits). Calculating a binary representation of pi anew would have had to be set up as a separate job. They didn't do that; they just chopped 4 bits off the 7090 binary floating point mantissa for the pi value. Ignoring rounding. So the least significant bit, which should have been rounded up to a 1, remained a 0. The professor's theoretical error estimates were based on a properly rounded, not a truncated pi value. This truncated 7090-binary pi value from the end of the 1950s was interited all the way up to the 3080 series, more than 20 years later. When discovered, and the least significant bit rounded up to a 1, the theoretical error estimates matched the observed errors more or less perfectly.

              1 Reply Last reply
              0
              • S swampwiz

                It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

                K Offline
                K Offline
                Kirk 10389821
                wrote on last edited by
                #21

                Well, it depends... First, rational numbers would slow things down. But if you want accuracy in math, I think the answer is to use integers with IMPLIED Decimals. Some currency types do this with 4 digits of implied decimal accuracy. Personally, I have never seen the need for more than this, unless I was using matlab or something where maintaing 1/3 of important to backing out of the problem properly. Finally, you could always implement your own classes to behave properly. Good luck with that, and the resulting speed. Kirk Out!

                K 1 Reply Last reply
                0
                • S swampwiz

                  It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

                  E Offline
                  E Offline
                  englebart
                  wrote on last edited by
                  #22

                  Smalltalk had a Fraction type that (I believe) worked like you would do it in elementary math. 1/3 -> new Fraction(1,3) (not the smalltalk notation!) 3/2 -> new Fraction(3,2) (1/3) * (3/2) = new Fraction(1,3) * new Fraction(3,2) = new Fraction(1,2) -> 1/2

                  1 Reply Last reply
                  0
                  • G gdemont

                    Already done : check Rationals @ http://mathpaqs.sourceforge.net/. It's even generic, so you can use whatever type for a,b in the fractions a/b: integers, big integers, polynomials, ...

                    K Offline
                    K Offline
                    kalberts
                    wrote on last edited by
                    #23

                    When we were CompSci students around 1980, ready-made packages were not readily available, so a group of us created an arbitrary precision arithmetic fortram package for a friend in theoretical physics: This fellow was working on an analythical model to describe, at the micro level, what happens when two wave fronts collide head on. When applying this model in a simulation, even the Univac 1100 double precision 72 bit floating point causd discontinuities - more or less perfect square wave forms, which none of us really believed existed in the physical world, certainly not in liquids... So we gave him a library where we set up buffers for 200 decimal digits. (For character I/O, BCD was much better suited than a 600+ bits pure binary value - speed of calculation was not of any importance.) Even with 600+ bits of precision, he experienced too large discontinuities. Then we realized that he was adding up elements of a series expansions from the head of the series, from the big towards the smaller elements. This lead us into a huge argument with him: As I said, he was in theoretical physics, and simply refused to accept that the order of adding together series elements would make a difference. We were several guys, over a period of many days, trying to explain, each in our own way, why "in theory, therory and practice are identical, but in practice they are not". Finally, he gave in and turned the addition around the other way. The waves came out so smooth that we silently suspected that the Univac 72 bits format would have been sufficient, if had just, from the very beginning, added the smallest elements first. There was an intense discussion in academia around that time whether Computer Science is a science requiring its own scientists to do computer related jobs, or if every engineer, mathmatician or physicist should learn to handle a computer himself. I several times used this story to argue that scientists getting close to a computer must learn enough about them to avoid silly problems caused by poor understanding of how computers operate.

                    1 Reply Last reply
                    0
                    • S swampwiz

                      It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

                      B Offline
                      B Offline
                      Bruce Patin
                      wrote on last edited by
                      #24

                      They had this in Assembler and FORTRAN a long time ago. In fact, it is a basic number type in System/370 machine language.

                      1 Reply Last reply
                      0
                      • K Kirk 10389821

                        Well, it depends... First, rational numbers would slow things down. But if you want accuracy in math, I think the answer is to use integers with IMPLIED Decimals. Some currency types do this with 4 digits of implied decimal accuracy. Personally, I have never seen the need for more than this, unless I was using matlab or something where maintaing 1/3 of important to backing out of the problem properly. Finally, you could always implement your own classes to behave properly. Good luck with that, and the resulting speed. Kirk Out!

                        K Offline
                        K Offline
                        kalberts
                        wrote on last edited by
                        #25

                        Kirk 10389821 wrote:

                        First, rational numbers would slow things down.

                        First, in quite a few applications, that doesn't matter. Whether the calculations are done in 10 or 20 milliseconds doesn't matter if you prepare a value that is displayed in an interactive dialog. Second, if arithmetic calculations is only a small part of the handling, other formats than the traditional floating point may be faster in the other operations. Take an archetypical Cobol application: It reads in, moves around and displays values in counts and dollars and cents; every now and then doing a multiplication, but mostly just addition and subtraction. The time saved in I/O from a BCD format compared to a float format greatly offsets the slower BCD addition/subtraction. Third: If you use rationals to avoid rounding errors, your float option might be an arbitrary precision float package. Adding 1/3 + 1/6 as rationals is likely to be much faster than calling a library function maintaining a list of mantiass elemnets to add 0.333333.... and 0.16666... for, say, 512 bits.

                        1 Reply Last reply
                        0
                        • G gdemont

                          Already done : check Rationals @ http://mathpaqs.sourceforge.net/. It's even generic, so you can use whatever type for a,b in the fractions a/b: integers, big integers, polynomials, ...

                          S Offline
                          S Offline
                          swampwiz
                          wrote on last edited by
                          #26

                          It says this project has no files.

                          1 Reply Last reply
                          0
                          • OriginalGriffO OriginalGriff

                            And storage of Pi would be?

                            Sent from my Amstrad PC 1640 Bad command or file name. Bad, bad command! Sit! Stay! Staaaay... AntiTwitter: @DalekDave is now a follower!

                            O Offline
                            O Offline
                            obermd
                            wrote on last edited by
                            #27

                            Still wouldn't help electrical engineers whose work is based on e and I. That said there are a lot of good reasons to support some sort of base 10 fractional numbers to avoid the rounding errors that result from converting base 2 fractionals to base 10 fractionals.

                            1 Reply Last reply
                            0
                            • S swampwiz

                              It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

                              D Offline
                              D Offline
                              Daniel Wilianto
                              wrote on last edited by
                              #28

                              With modern language I think you can implement it yourself. All C# variable types derive from System.Object anyway. And then you can override arithmatic operator for this new type. I can sort of picture it, storing each value as two integer : numerator and denominator.

                              K 1 Reply Last reply
                              0
                              • D Daniel Wilianto

                                With modern language I think you can implement it yourself. All C# variable types derive from System.Object anyway. And then you can override arithmatic operator for this new type. I can sort of picture it, storing each value as two integer : numerator and denominator.

                                K Offline
                                K Offline
                                kalberts
                                wrote on last edited by
                                #29

                                I wouldn't hesitate for a second to give that as the exercise of the week to second year programming students, implmenting the four basic arithmetic operations for rationals. There is only a small problem: If the denominators are not identical in addition/subtraction, you can trivially find a common denominator by multiplying the two, but in the genral case, it is not the least common denominator. If you use 64 bit integers for the denominator you might delay handling this until the results are to be used (at least for small student level applications), but at some stage you will have to factorize the numerator and denominator, and remove common factors. In principle this is not difficult as long as the problem is of "student size", but Eratosthenes' sieve is not very efficient (certainly not in space!) - you wouldn't want to employ that for every addition or subtraction! Factors of 2 are easy to get rid of: While both (numerator AND 1) and (denominator ANd 1) are nonzero, shift both right by one bit. This you can do for every basic arithmetic operation (or complex expression). Other factors are worse. If you find it acceptable to do a whole series of division/remainder operations (trying with all prime factors up to the square root of the smaller of numerator and denominator), then the space required is roughly limited to a single read-only table of known primes, but you'll certainly be keeping the division circuitry of the CPU hot :-). My recommendation would be to delay the factorization until it is needed for presentation or conversion to other formats. Viewing/interpreting the values through a debugger would be a next to impossible, and you should implement an exception handler removing common factors if an operation would cause the numerator/denominator to overflow the integer format - maybe doing a 2-factor removal as a fast first try, and going on to a series of division operations only if the values are still above a certain overflow risk threshold. If you use 64 bit ints, you might in the worst case have to do divisions for every prime less than 4G; that is quite some operation...

                                1 Reply Last reply
                                0
                                • S swampwiz

                                  It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

                                  V Offline
                                  V Offline
                                  Vivi Chellappa
                                  wrote on last edited by
                                  #30

                                  Not all that hard. In my MS Computer Science course, All students had to write a compiler for a language that had only integers and rational numbers. This was before the days of C++, classes, etc. Not too much of a sweat.

                                  K 1 Reply Last reply
                                  0
                                  • V Vivi Chellappa

                                    Not all that hard. In my MS Computer Science course, All students had to write a compiler for a language that had only integers and rational numbers. This was before the days of C++, classes, etc. Not too much of a sweat.

                                    K Offline
                                    K Offline
                                    kalberts
                                    wrote on last edited by
                                    #31

                                    How did you handle the (least common) denominator problem? Or did you simply ignore it, ignoring the risk that it might overflow? How did you present the results - as if they were floats (through a "(float)numerator/(float)denominator" division) using float output format? Did you do anything to detect common denominators, or did 1/3 + 1/3 end up as 6/9?

                                    V 1 Reply Last reply
                                    0
                                    • K kalberts

                                      How did you handle the (least common) denominator problem? Or did you simply ignore it, ignoring the risk that it might overflow? How did you present the results - as if they were floats (through a "(float)numerator/(float)denominator" division) using float output format? Did you do anything to detect common denominators, or did 1/3 + 1/3 end up as 6/9?

                                      V Offline
                                      V Offline
                                      Vivi Chellappa
                                      wrote on last edited by
                                      #32

                                      I don't remember the details because it was such a long time ago but I distinctly remember that I did determine the least common denominator for fractions and ensured that all rational numbers were stored in their reduced form.

                                      1 Reply Last reply
                                      0
                                      • S swampwiz

                                        It seems to me that there could be a type (implemented in your favorite language has has classes, including operator overloading) that would store a number as a rational number. This type would be a list of links that would have prime factors and their exponents (e.g., in C++, the prime factor would be type "unsigned long", with the exponent being "long"). This would work because any decimal (or hexadecimal) input would be a rational number itself, and then any operations would be exact, so that, e.g., the result of (213.56 - 45.41) would be 168.15 and not 168.14999999, etc.

                                        B Offline
                                        B Offline
                                        bjongejan
                                        wrote on last edited by
                                        #33

                                        While a rational number type has both advantages and disadvantages and we can discuss that forever, it is an undeniable truth that JSON should have had a rational number type, simply because some languages or libraries already support rational numbers and there should exist a portable way for applications using rational numbers to serialize and exchange these with other applications. A rational number that is within the range of a floating point number type can always be "downgraded" to that floating point number type, but the converse is problematic. For example, is the JSON expression [0.67,0.33] an array with the numbers 2/3 and 1/3 ? If not, then what about [0.6666666666666667,0.3333333333333333]? It would have been clear what was meant if we were allowed to write [2/3,1/3].

                                        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