- rational numbers - 12 Updates
| alessandro volturno <alessandro.volturno@libero.it>: Sep 16 02:59PM +0200 Hello group, I am writing some C++ code to implement a class that handles fractional numbers. C++11 has the Ratio facility, but it is not possible to instantiate Ratio objects or pass them to functions (at least I was not able to do that), so just for fun I started a simple rational class, adding the following: private members *num* and *den* constructor; destructor; // defaulted copy assignment operator // defaulted copy constructor // defaulted move assignment operator // defaulted move constructor // defaulted operator+ () operator- () operator* () operator/ () operator== () operator!= () friend operator<= () friend operator< () friend operator> () friend operator>= () friend operator<< () friend operator>> () printDescription() // prints a description of the number and its // numerical value reduce() // simplifies a fraction using a static GCD function reciprocal() // inverts a rational number Maybe my question is stupid, but why not to introduce a way to handle rational numbers inside the C++ standard or better make it a built in type? |
| Paavo Helde <myfirstname@osa.pri.ee>: Sep 16 04:40PM +0300 16.09.2021 15:59 alessandro volturno kirjutas: > Maybe my question is stupid, but > why not to introduce a way to handle rational numbers inside the C++ > standard or better make it a built in type? What are the use cases for rationals? If something is not in the standard, then often there are different use cases which cannot be easily covered by a common "standard" implementation. For rationals it feels like a fast implementation would have a pretty limited numeric range, and unlimited range would require arbitrary precision integers and would probably be many times slower even in case of small numbers. Nevertheless, there is at least one proposal to include rationals in the standard, see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3363.html Meanwhile one can use the Boost Rational library. |
| alessandro volturno <alessandro.volturno@libero.it>: Sep 16 06:24PM +0200 Il 16/09/2021 15:40, Paavo Helde ha scritto: >> Maybe my question is stupid, but >> why not to introduce a way to handle rational numbers inside the C++ >> standard or better make it a built in type? I speak as a non-competent, hobbyist programmer and computer-user. > What are the use cases for rationals? If something is not in the > standard, then often there are different use cases which cannot be > easily covered by a common "standard" implementation. Computers were born to manipulate numbers and the languages for doing that, at that time, were mainly two: FORTRAN, and LISP. I have noticed that C++ (that I presume it could be thought of as a descendant of FORTRAN, is shifting towards Functional programming language facilities, like that offered by the LISP family. That's good, but numerical programming is still important nowadays. > limited numeric range, and unlimited range would require arbitrary > precision integers and would probably be many times slower even in case > of small numbers. Mine uses long long int, that is the maximum offered by the language, but calculation speed is constantly increasing. I don't see that a as a limiting factor. True that C++ applications can be built for every available hardware configuration (and so they can be run on older or slower cpus), but rational are an important class of numbers and its family is wider than integers' > Nevertheless, there is at least one proposal to include rationals in the > standard, see > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3363.html The proposal you presented is quite dated, so I presume many talkings have been made about it. I don't know the reason why, but it evidently came out not to add this feature to the language. Many computer languages are evolving and new ones are born every one or two years. In my opinion, to keep a language competitive with respect to the others around, that language should also permit basic number manipulation as easier as possible. I repeat myself, I'm a hobbyist, spare-time programmer, but as complex numbers have been added to C++, so there should be some mechanics to handle rationals. > Meanwhile one can use the Boost Rational library. I've heard about the Boost library but I've never made an attempt to study it nor to use it. My projects are small ones and I write them by scratch just for the sake of knowing how I progress in this discipline (computer programming). Thank you for your kind reply, alessandro |
| scott@slp53.sl.home (Scott Lurndal): Sep 16 05:05PM >FORTRAN, is shifting towards Functional programming language facilities, >like that offered by the LISP family. That's good, but numerical >programming is still important nowadays. I suspect that the vast majority of people use existing software packages like Matlab or R (for statistics) than write C++ code for numerical software nowadays. It's really hard to get it right when using binary floating point, hence standard numerical libraries (LINPACK, et alia). https://en.wikipedia.org/wiki/List_of_numerical_libraries |
| Manfred <noname@add.invalid>: Sep 16 07:58PM +0200 On 9/16/2021 7:05 PM, Scott Lurndal wrote: > right when using binary floating point, hence standard numerical > libraries (LINPACK, et alia). > https://en.wikipedia.org/wiki/List_of_numerical_libraries It is true that numerical analysis is easier in Matlab than C++, but I think the main point is that, if you know what you are doing, standard floating point and integer types can cover the a lot of application use even when writing C++ (as well as C) programs. The main advantage of rational arithmetic is that it allows an exact representation of a significant class of numbers, without rounding errors. But in many practical applications (engineering, automation, ...) 16 significant digits (as offered by the 'double' type) yield rounding errors that are small enough. It is true, though, that specific knowledge is required - naive code can easily yield garbage. The limitation that I see with digital rationals, without having read the linked proposal, is that they would still represent a limited subset of the rational numbers, which is a limitation for theoretical analysis - in addition, output results can be exact only if inputs are exact rationals numbers, which rules out all physical quantities, a limitation of the advantage over floating point math. In short, it is understandable that there is not enough motivation to include this as a native type in the language, compared to what is already available through libraries. |
| David Brown <david.brown@hesbynett.no>: Sep 16 08:41PM +0200 On 16/09/2021 18:24, alessandro volturno wrote: > configuration (and so they can be run on older or slower cpus), but > rational are an important class of numbers and its family is wider than > integers' There are two key difficulties about constructive use of rationals. One is that you have to handle reduction by greatest common denominator - that is not a simple operation, but is time-consuming and has unpredictable timing. The other is that the sizes of the denominator and numerator very quickly get very big for all but the simplest of calculations - you don't have to do a lot with them before the arithmetic becomes impossible within the fixed size framework. (This is in comparison to complex numbers, which are easy.) Basically, I don't think there is that much need of rationals of fixed size - you can usually make do with floating point or integers, or you need arbitrary precision. Rationals are very important in mathematics, much less so in practical programming. However, as a hobby task, a good set of rational number classes would be great fun to work on. You can start with a basic implementation, then work on a templated version handling different sizes, learn about concepts with a practical use-case, figure how to make everything constexpr, get neat ways to make bigger fixed-size rational types, explore ways to handle overflows. The scope for enjoyment and learning is huge here. |
| Bart <bc@freeuk.com>: Sep 16 09:11PM +0100 On 16/09/2021 19:41, David Brown wrote: > calculations - you don't have to do a lot with them before the > arithmetic becomes impossible within the fixed size framework. (This is > in comparison to complex numbers, which are easy.) You get a similar problem with arbitrary precision floats. (At least, in my library. I don't know how others deal with it; I use upper limits on precision). Multiply two numbers with M and N digits of precision respectively, and the result will have M*N digits of precision, without the magnitude necessarily getting bigger. It's worse with divide: just do 1.0/3.0, and it will be calculating 0.3333.... forever (the theoretical limit in mine is 36 billion digits, but it will be aborted, long before). At least with rationals, this can be deferred, or cancelled out if the next thing is to multiply by 3 again. > constexpr, get neat ways to make bigger fixed-size rational types, > explore ways to handle overflows. The scope for enjoyment and learning > is huge here. I've often reserved a rational type in the languages I create, but have never got round to implementing them. They will usually need a big-integer type for a start. But as you say they are not that practical. How would they be displayed for example; as proper and improper fractions? I get enough grief when my Casio gets stuck in fraction mode and I can't remember how to fix it. |
| Paavo Helde <myfirstname@osa.pri.ee>: Sep 16 11:12PM +0300 16.09.2021 19:24 alessandro volturno kirjutas: > FORTRAN, is shifting towards Functional programming language facilities, > like that offered by the LISP family. That's good, but numerical > programming is still important nowadays. Of course numerical programming is important. It's done mostly in floating-point (64-bit and 32-bit; in recent years also 16-bit on GPU-s). In some cases it can be done in integers, for more speed, but it's not so simple and the speedups are not very large any more nowadays. I notice that you still haven't presented any use case for rationals. I have to admit I also wrote a C++ class for rational numbers ca 20 years ago, but so far I have not found any usage for it in my work (which also involves a lot of heavy numeric computations). > Mine uses long long int, that is the maximum offered by the language, > but calculation speed is constantly increasing. I don't see that a as a > limiting factor. Long long int probably means 64 bits, which is not so much. The smallest positive rational would be 1/2^64, i.e. ca 10^-61. Meanwhile, the smallest positive double is ca 10^-308, with the same number of bits. Ditto for the largest values. IOW, floating-point can approximate values with much more precision, and there is much less danger of overflows during computations. The only advantage what rationals offer above floating-point is that the calculation results are always exact. However, in numeric programming the input data often comes from a physical measurement, meaning that it already contains measurement inaccuracies. Thus the end result will not be absolutely accurate anyway, so there is no need to use absolutely precise computations. Sure, with floating-point algorithms one must take care to not lose too much precision in intermediate results. However, I suspect that with rational number algorithms even more care is needed, to avoid numeric overflows in intermediate results. [...] > Thank you for your kind reply, Thanks! |
| Ben Bacarisse <ben.usenet@bsb.me.uk>: Sep 16 09:26PM +0100 > Multiply two numbers with M and N digits of precision respectively, > and the result will have M*N digits of precision, without the > magnitude necessarily getting bigger. That sounds odd. If it's binary FP, multiplying 2 by 2 need not result in a result with more digits than the already exact operands. Do you always widen the mantissa in a multiplication? -- Ben. |
| Bart <bc@freeuk.com>: Sep 16 09:54PM +0100 On 16/09/2021 21:26, Ben Bacarisse wrote: > That sounds odd. If it's binary FP, multiplying 2 by 2 need not result > in a result with more digits than the already exact operands. Do you > always widen the mantissa in a multiplication? (My library is decimal, but there will be the same issues with binary.) I think I meant M+N, not M*N! And that's approximate. Squaring a single digit 1-9 will result in 1-81, which is 1 or 2 digits. (M*N applies to exponentiation.) In any case, it will increase the number of digits when chaining a lot of multiplications, when you have no upper limit on precision. There is some confusion since digits or bits don't usually exist by themselves, but grouped into words or 'limbs'. Squaring 31 bits of value contained within a 64-bit type yields something that still fits into 64 bits, but may need 61/62 of those bits to represent. But this is about arbitrary precision with multiple words to store results. |
| "Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Sep 16 11:07PM +0200 On 16 Sep 2021 22:26, Ben Bacarisse wrote: > That sounds odd. If it's binary FP, multiplying 2 by 2 need not result > in a result with more digits than the already exact operands. Do you > always widen the mantissa in a multiplication? I think Ben meant to write M + N, not M*N. :-o Consider the product of A = a*r^n and B = b*r^m, where a and b are integers and r is the numeral system radix. You get a result C = A*B = a*b*r^(n+m), where the number of digits of C is roughly (the number of digits of a) + (the number of digits of b). - Alf |
| "Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Sep 16 11:27PM +0200 On 16 Sep 2021 23:07, Alf P. Steinbach wrote: > integers and r is the numeral system radix. > You get a result C = A*B = a*b*r^(n+m), where the number of digits of C > is roughly (the number of digits of a) + (the number of digits of b). I evidently meant to write "Bart", not "Ben". Oh well. - Alf |
| You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment