When should I use the inexact number prefix (#i)? - racket

If I understand correctly, numbers in Racket are inexact by default. So under what conditions should I explicitly use the inexact number prefix (#i)? What is it for?

Numbers in Racket are not inexact by default. E.g., rationals and integers (without .0) are exact.
So for me, I'd use #i when I want to write an inexact number that is close to a rational number. Something like #i22/7.

Related

Why does Racket report that π is rational?

As any secondary math student can attest, pi is irrational.
And yet:
Welcome to Racket v5.3.6.
> pi
3.141592653589793
> (rational? pi)
#t
Is this because the representation of pi, in the underlying machine's floating point format, is of limited precision and therefore can always be expressed as some p/q where q is 10^n, and n is the representational precision ?
If so, how could any number thrown about by Racket (or other similarly-behaving scheme) ever be considered anything but rational? And hence, why bother with the rational? function?
UPDATE: Even (rational? (sqrt 3)) reports #t
The number returned by pi is rational because the documentation says so. Specifically it says:
All numbers are complex numbers. Some of them are real numbers, and all of the real numbers that can be represented are also rational numbers, except for +inf.0 (positive infinity), +inf.f (single-precision variant), -inf.0 (negative infinity), -inf.f (single-precision variant), +nan.0 (not-a-number), and +nan.f (single-precision variant). Among the rational numbers, some are integers, because round applied to the number produces the same number.
So your hunch is right. All representable real numbers are indeed rational (except for the infinities and NaNs) because, yes, numbers are stored in fixed-size registers so the machine isn't going to store an irrational number.
As to why the Racket designers bothered with a rational? function, that is a good question. Many languages like Julia and Clojure have a real, actual, honest-to-goodness rational datatype. Racket doesn't, so, as you suspect, it does seem silly to define a near-complete subset of the reals as rationals.
But you know, it just may be convenient to have a way to talk about a non-NaN, non-Infinity value. I would have called it finite, but Racket calls it rational.

Define single precision variable in Racket

I have to run some computations in Racket that I have never used before.
How do I force it to calculate sth in single or half (if it has those) precision floats?
I figured out how to make it compute in big floats:
(bf/ (bf 1) (bf 7))
I know that the abbreviation for floats (double precision) is fl. I cannot figure out the right abbreviation for single floats though.
The 'bigfloat' package you refer to are for arbitrary precision floating point numbers. You're very unlikely to want these, as you point out.
It sounds like you're looking for standard IEEE 64-bit floating point numbers. Racket uses these by default, for all inexact arithmetic.
So, for instance:
(/ 1 pi)
produces
0.3183098861837907
One possible tripper-upper is that when dividing two rational numbers, the result will again be a rational number. So, for instance,
(/ 12347728 298340194)
produces
6173864/149170097
You can force inexact arithmetic either by using exact->inexact (always works), or by ensuring that your literals end with decimals (unless you're using the htdp languages).
So, for instance:
(/ 12347728.0 298340194.0)
produces
0.04138808061511148
Let me know if this doesn't answer your question....

How to round the result of a division in intersystems cache?

What's the best way to round the result of a division in intersystems cache?
Thanks.
There are some functions, which used to format numbers, as well they would round it if necessary
$justify(expression,width[,decimal]) - Caché rounds or pads the number of fractional digits in expression to this value.
write $justify(5/3,0,3)
1.667
$fnumber(inumber,format,decimal)
write $fnumber(5/3,"",3)
1.667
$number(num,format,min,max)
write $number(5/3,3)
1.667
$normalize(num,scale)
w $normalize(5/3,3)
1.667
You just can choose which of them much more suitable for you. They doing different things, but result could be same.
In standard MUMPS (which Cache Object Script is backwards compatible with)
there are three "division" related operators. The first is the single character "/" (i.e. forward slash). This is a real number divide. 5/2 is 2.5, 10.5/5 is 2.1, etc. This takes two numbers (each possibly including a decimal point and a fraction ) and returns a number possibly with a fraction. A useful thing to remember is that this numeric divide yields results that are as simple as they can be. If there are leading zeros in front of the decimal point like 0007 it will treat the number as 7.
If there are trailing zeros after the decimal point, they will be trimmed as well.
So 2.000 gets trimmed to 2 (notice no decimal point) and 00060.0100 would be trimmed to just 60.01
In the past, many implementors would guarantee that 3/3 would always be 1 (not .99999) and that math was done as exactly as could be done. This is not an emphasis now, but there used to be special libraries to handle Binary Coded Decimal, (BCD) to guarantee as close to possible that fractions of a penny were never generated.
The next division operator was the single character "\" (i.e. backward slash).
this operator was called integer division or "div" by some folks. It would
do the division and throw away any remainder. The interesting thing about this is that it would always result in an integer, but the inputs didn't have to be an integer. So 10\2 is 5, but 23\2.3 is 10 and so is 23.3\2.33 , If there would be a fraction left over, it is just dropped. So 23.3\2.3 is 10 as well. The full divide operator would give you many fractions. 23.3/2.3 is 10.130434 etc.
The final division operator is remainder (or "mod" or "modulo"), symbolized by the single character "#" (sometimes called hash, pound sign, or octothorpe). To get the answer for this one, the integer division "/" is calculated, and what ever is left over when an integer division is calculated will be the result. In our example of 23\2 the answer is 11 and the remaining value is 1, so 23#2 is 1
ad 23.3#2.3 is .3 You may notice that (number#divisor)+((number\divisior)*divisor) is always going to be your original number back.
Hope this helps you make this idea clear in your programming.

comparing float and double and printing them

I have a quick question. So, say I have a really big number up to like 15 digits, and I would take the input and assign it to two variables, one float and one double if I were to compare two numbers, how would you compare them? I think double has the precision up to like 15 digits? and float has 8? So, do I simply compare them while the float only contains 8 digits and pad the rest or do I have the float to print out all 15 digits and then make the comparison? Also, if I were asked to print out the float number, is the standard way of doing it is just printing it up to 8 digits? which is its max precision
thanks
Most languages will do some form of type promotion to let you compare types that are not identical, but reasonably similar. For details, you would have to indicate what language you are referring to.
Of course, the real problem with comparing floating point numbers is that the results might be unexpected due to rounding errors. Most mathematical equivalences don't hold for floating point artihmetic, so two sequences of operations which SHOULD yield the same value might actually yield slightly different values (or even very different values if you aren't careful).
EDIT: as for printing, the "standard way" is based on what you need. If, for some reason, you are doing monetary computations in floating point, chances are that you'll only want to print 2 decimal digits.
Thinking in terms of digits may be a problem here. Floats can have a range from negative infinity to positive infinity. In C# for example the range is ±1.5 × 10^−45 to ±3.4 × 10^38 with a precision of 7 digits.
Also, IEEE 754 defines floats and doubles.
Here is a link that might help http://en.wikipedia.org/wiki/IEEE_floating_point
Your question is the right one. You want to consider your approach, though.
Whether at 32 or 64 bits, the floating-point representation is not meant to compare numbers for equality. For example, the assertion 2.0/7.0 == 60.0/210.0 may or may not be true in the CPU's view. Conceptually, the floating-point is inherently meant to be imprecise.
If you wish to compare numbers for equality, use integers. Consider again the ratios of the last paragraph. The assertion that 2*210 == 7*60 is always true -- noting that those are the integral versions of the same four numbers as before, only related using multiplication rather than division. One suspects that what you are really looking for is something like this.

How to eliminate Perl rounding errors

Consider the following program:
$x=12345678901.234567000;
$y=($x-int($x))*1000000000;
printf("%f:%f\n",$x,$y);
Here's what is prints:
12345678901.234568:234567642.211914
I was expecting:
12345678901.234567:234567000
This appears to be some sort of rounding issue in Perl.
How could I change it to get 234567000 instead?
Did I do something wrong?
This is a frequently-asked question.
Why am I getting long decimals (eg, 19.9499999999999) instead of the numbers I should be getting (eg, 19.95)?
Internally, your computer represents floating-point numbers in binary. Digital (as in powers of two) computers cannot store all numbers exactly. Some real numbers lose precision in the process. This is a problem with how computers store numbers and affects all computer languages, not just Perl.
perlnumber shows the gory details of number representations and conversions.
To limit the number of decimal places in your numbers, you can use the printf or sprintf function. See the Floating Point Arithmetic for more details.
printf "%.2f", 10/3;
my $number = sprintf "%.2f", 10/3;
Make "use bignum;" the first line of your program.
Other answers explain what to expect when using floating point arithmetic -- that some digits towards the end are not really part of the answer. This is to make the computations do-able in a reasonable amount of time and space. If you are willing to use unbounded time and space to work with numbers, then you can use arbitrary-precision numbers and math, which is what "use bignum" enables. It's slower and uses more memory, but it works like math you learned in elementary school.
In general, it's best to learn more about how floating point math works before converting your program to arbitrary-precision math. It's only needed in very strange situations.
The whole issue of floating point precision has been answered, but you're still seeing the problem despite bignum. Why? The culprit is printf. bignum is a shallow pragma. It only affects how numbers are represented in variables and math operations. Even though bignum makes Perl do the math right, printf is still implemented in C. %f takes your precise number and turns it right back into an imprecise floating point number.
Print your numbers with just print and they should do fine. You'll have to format them manually.
The other thing you can do is to recompile Perl with -Duse64bitint -Duselongdouble which will force Perl to internally use 64 bit integers and long double floating point numbers. This will give you a lot more accuracy, more consistently and almost no performance cost (bignum is a bit of a performance hog for math intensive code). Its not 100% accurate like bignum, but it will affect things like printf. However, recompiling Perl this way makes it binary incompatible, so you're going to have to recompile all your extensions. If you do this, I suggest installing a fresh Perl in a different location (/usr/local/perl/64bit or something) rather than trying to manage parallel Perl installs sharing the same library.
Homework (Googlework?) for you: How are floating point numbers represented by computers?
You can only have a limited number of precise digits, everything beyond that is just the noise from base conversion (binary to decimal). That is also why the last digit of your $x appears to be 8.
$x - (int($x) is 0.23456linenoise, which is also a floating point number. Multiplied by 1000000000, it gives another floating point number, with more random digits pulled from the incommensurability of the bases.
Perl does not do arbitrary precision arithmetic for its built-in floating point types. So your initial variable $x is an approximation. You can see this by doing:
$ perl -e 'printf "%.10f", 12345678901.234567000'
12345678901.2345676422
This answer works on my x64 platform, by accommodating the scale of the errors
sub safe_eq {
my($var1,$var2)=#_;
return 1 if($var1==$var2);
my $dust;
if($var2==0) { $dust=abs($var1); }
else { $dust= abs(($var1/$var2)-1); }
return 0 if($dust>5.32907051820076e-15 ); # 5.32907051820075e-15
return 1;
}
You can build on the above to solve most of your problems.
Avoid bignum if you can - it's stupendously slow - plus it will not solve any problems if you've got to store your numbers anyplace like a DB or in JSON etc.
This has to do with the (limited) accuracy of the floating point computations a computer does. Generally when comparing floating point numbers you should compare with a suitable epsilon:
$value1 == $value2 or warn;
won't work as expected in most cases. You should do
use constant EPSILON => 1.0e-10;
abs($value1 - $value2) < EPSILON or warn;
EPSILON should be chosen such that it takes into account the complexity of the computations for valueX. A large computation might lead to a much, much larger EPSILON.
The other option is, as suggested by others:
sprintf("%.5f", value1) eq sprintf("%.5f", value2) or warn;
Or use an arbitrary precision math library.