Thursday, September 16, 2021

Digest for comp.lang.c++@googlegroups.com - 12 updates in 1 topic

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: