Scala Simple calculation error [duplicate] - scala

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
Hi I am new to Scala and the following behavior is really weird. Is Scala making mistake even for this simple calculation? Or I am doing something wrong?
Thanks,
scala $ Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> val radius:Double = 10.2
radius: Double = 10.2
scala> radius * 10
res0: Double = 102.0
scala> radius * 100
res1: Double = 1019.9999999999999
scala> radius * 1000
res2: Double = 10200.0

A Double in Scala is a 64-bit IEEE-754 floating point number equivalent to Java's double primitive type, as described in Scala's doc.
By nature of floating point number, a Double doesn't necessarily return the exact value of a number. It boils down to the fact that decimals can't always be precisely represented as binary.
For better precision, you might want to consider using BigDecimal.

Real numbers are represented by Float (32-bit) and Double (64-bit). These are binary formats which only approximately represent the complete range of Real numbers. Real numbers include all the Rationals (countable infinite), and the Irrationals (uncountable infinite). Double can at best represent only a small, finite subset of the Rationals.
The IEEE-754 double precision floating point encoding uses 53-bit mantissa (52-bits explicitly stored), an 11-bit exponent, and 1-bit for sign. Read about IEEE Double precision floating point here.
The range of integers which can be exactly represented is +/- 2^53-1, while the exponent represents a range of 10^+/-308.
You cannot express an integer x exactly where |x| > 2^53.
You cannot express fractions exactly which are not of the form k/2^n, where k, n are integers (and k, n are within above limits). Thus, you cannot represent 1/3, 1/5, 1/7, 1/11, etc.
Any rational fraction where the denominator is relatively prime to 2 cannot be exactly represented. Any fraction k/P, where P is the product of primes other than 2, and k is not a multiple of P, cannot be exactly represented by IEEE-754 floating point.
The behavior you are observing is due to 1/5 being approximately represented, and the conversion from internal double/float representation to character representation performs rounding to some precision. All languages which use machine floating point (double/float) exhibit similar behavior, but the routines which convert from float to print may round these approximate numbers differently.
As a consequence of Cantor's proof that the Real numbers are uncountable and the Rational numbers are countable, almost all Real numbers are irrational.

Related

How is Powershell rounding Doubles when multiplying with Strings? [duplicate]

In C#, the result of Math.Round(2.5) is 2.
It is supposed to be 3, isn't it? Why is it 2 instead in C#?
Firstly, this wouldn't be a C# bug anyway - it would be a .NET bug. C# is the language - it doesn't decide how Math.Round is implemented.
And secondly, no - if you read the docs, you'll see that the default rounding is "round to even" (banker's rounding):
Return ValueType: System.DoubleThe integer nearest a. If the
fractional component of a is halfway
between two integers, one of which is
even and the other odd, then the even
number is returned. Note that this
method returns a Double instead of an
integral type.
RemarksThe behavior of this method follows IEEE Standard 754,
section 4. This kind of rounding is
sometimes called rounding to nearest,
or banker's rounding. It minimizes
rounding errors that result from
consistently rounding a midpoint value
in a single direction.
You can specify how Math.Round should round mid-points using an overload which takes a MidpointRounding value. There's one overload with a MidpointRounding corresponding to each of the overloads which doesn't have one:
Round(Decimal) / Round(Decimal, MidpointRounding)
Round(Double) / Round(Double, MidpointRounding)
Round(Decimal, Int32) / Round(Decimal, Int32, MidpointRounding)
Round(Double, Int32) / Round(Double, Int32, MidpointRounding)
Whether this default was well chosen or not is a different matter. (MidpointRounding was only introduced in .NET 2.0. Before then I'm not sure there was any easy way of implementing the desired behaviour without doing it yourself.) In particular, history has shown that it's not the expected behaviour - and in most cases that's a cardinal sin in API design. I can see why Banker's Rounding is useful... but it's still a surprise to many.
You may be interested to take a look at the nearest Java equivalent enum (RoundingMode) which offers even more options. (It doesn't just deal with midpoints.)
That's called rounding to even (or banker's rounding), which is a valid rounding strategy for minimizing accrued errors in sums (MidpointRounding.ToEven). The theory is that, if you always round a 0.5 number in the same direction, the errors will accrue faster (round-to-even is supposed to minimize that) (a).
Follow these links for the MSDN descriptions of:
Math.Floor, which rounds down towards negative infinity.
Math.Ceiling, which rounds up towards positive infinity.
Math.Truncate, which rounds up or down towards zero.
Math.Round, which rounds to the nearest integer or specified number of decimal places. You can specify the behavior if it's exactly equidistant between two possibilities, such as rounding so that the final digit is even ("Round(2.5,MidpointRounding.ToEven)" becoming 2) or so that it's further away from zero ("Round(2.5,MidpointRounding.AwayFromZero)" becoming 3).
The following diagram and table may help:
-3 -2 -1 0 1 2 3
+--|------+---------+----|----+--|------+----|----+-------|-+
a b c d e
a=-2.7 b=-0.5 c=0.3 d=1.5 e=2.8
====== ====== ===== ===== =====
Floor -3 -1 0 1 2
Ceiling -2 0 1 2 3
Truncate -2 0 0 1 2
Round(ToEven) -3 0 0 2 3
Round(AwayFromZero) -3 -1 0 2 3
Note that Round is a lot more powerful than it seems, simply because it can round to a specific number of decimal places. All the others round to zero decimals always. For example:
n = 3.145;
a = System.Math.Round (n, 2, MidpointRounding.ToEven); // 3.14
b = System.Math.Round (n, 2, MidpointRounding.AwayFromZero); // 3.15
With the other functions, you have to use multiply/divide trickery to achieve the same effect:
c = System.Math.Truncate (n * 100) / 100; // 3.14
d = System.Math.Ceiling (n * 100) / 100; // 3.15
(a) Of course, that theory depends on the fact that your data has an fairly even spread of values across the even halves (0.5, 2.5, 4.5, ...) and odd halves (1.5, 3.5, ...).
If all the "half-values" are evens (for example), the errors will accumulate just as fast as if you always rounded up.
You should check MSDN for Math.Round:
The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called rounding to nearest, or banker's rounding.
You can specify the behavior of Math.Round using an overload:
Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // gives 3
Math.Round(2.5, 0, MidpointRounding.ToEven); // gives 2
From MSDN, Math.Round(double a) returns:
The integer nearest a. If the
fractional component of a is halfway
between two integers, one of which is
even and the other odd, then the even
number is returned.
... and so 2.5, being halfway between 2 and 3, is rounded down to the even number (2). this is called Banker's Rounding (or round-to-even), and is a commonly-used rounding standard.
Same MSDN article:
The behavior of this method follows
IEEE Standard 754, section 4. This
kind of rounding is sometimes called
rounding to nearest, or banker's
rounding. It minimizes rounding errors
that result from consistently rounding
a midpoint value in a single
direction.
You can specify a different rounding behavior by calling the overloads of Math.Round that take a MidpointRounding mode.
The nature of rounding
Consider the task of rounding a number that contains a fraction to, say, a whole number. The process of rounding in this circumstance is to determine which whole number best represents the number you are rounding.
In common, or 'arithmetic' rounding, it is clear that 2.1, 2.2, 2.3 and 2.4 round to 2.0; and 2.6, 2.7, 2.8 and 2.9 to 3.0.
That leaves 2.5, which is no nearer to 2.0 than it is to 3.0. It is up to you to choose between 2.0 and 3.0, either would be equally valid.
For minus numbers, -2.1, -2.2, -2.3 and -2.4, would become -2.0; and -2.6, 2.7, 2.8 and 2.9 would become -3.0 under arithmetic rounding.
For -2.5 a choice is needed between -2.0 and -3.0.
Other forms of rounding
'Rounding up' takes any number with decimal places and makes it the next 'whole' number. Thus not only do 2.5 and 2.6 round to 3.0, but so do 2.1 and 2.2.
Rounding up moves both positive and negative numbers away from zero. Eg. 2.5 to 3.0 and -2.5 to -3.0.
'Rounding down' truncates numbers by chopping off unwanted digits. This has the effect of moving numbers towards zero. Eg. 2.5 to 2.0 and -2.5 to -2.0
In "banker's rounding" - in its most common form - the .5 to be rounded is rounded either up or down so that the result of the rounding is always an even number. Thus 2.5 rounds to 2.0, 3.5 to 4.0, 4.5 to 4.0, 5.5 to 6.0, and so on.
'Alternate rounding' alternates the process for any .5 between rounding down and rounding up.
'Random rounding' rounds a .5 up or down on an entirely random basis.
Symmetry and asymmetry
A rounding function is said to be 'symmetric' if it either rounds all numbers away from zero or rounds all numbers towards zero.
A function is 'asymmetric' if rounds positive numbers towards zero and negative numbers away from zero.. Eg. 2.5 to 2.0; and -2.5 to -3.0.
Also asymmetric is a function that rounds positive numbers away from zero and negative numbers towards zero. Eg. 2.5 to 3.0; and -2.5 to -2.0.
Most of time people think of symmetric rounding, where -2.5 will be rounded towards -3.0 and 3.5 will be rounded towards 4.0. (in C# Round(AwayFromZero))
The default MidpointRounding.ToEven, or Bankers' rounding (2.5 become 2, 4.5 becomes 4 and so on) has stung me before with writing reports for accounting, so I'll write a few words of what I found out, previously and from looking into it for this post.
Who are these bankers that are rounding down on even numbers (British bankers perhaps!)?
From wikipedia
The origin of the term bankers'
rounding remains more obscure. If this
rounding method was ever a standard in
banking, the evidence has proved
extremely difficult to find. To the
contrary, section 2 of the European
Commission report The Introduction of
the Euro and the Rounding of Currency
Amounts suggests that there had
previously been no standard approach
to rounding in banking; and it
specifies that "half-way" amounts
should be rounded up.
It seems a very strange way of rounding particularly for banking, unless of course banks use to receive lots of deposits of even amounts. Deposit £2.4m, but we'll call it £2m sir.
The IEEE Standard 754 dates back to 1985 and gives both ways of rounding, but with banker's as the recommended by the standard. This wikipedia article has a long list of how languages implement rounding (correct me if any of the below are wrong) and most don't use Bankers' but the rounding you're taught at school:
C/C++ round() from math.h rounds away from zero (not banker's rounding)
Java Math.Round rounds away from zero (it floors the result, adds 0.5, casts to an integer). There's an alternative in BigDecimal
Perl uses a similar way to C
Javascript is the same as Java's Math.Round.
From MSDN:
By default, Math.Round uses
MidpointRounding.ToEven. Most people
are not familiar with "rounding to
even" as the alternative, "rounding
away from zero" is more commonly
taught in school. .NET defaults to
"Rounding to even" as it is
statistically superior because it
doesn't share the tendency of
"rounding away from zero" to round up
slightly more often than it rounds
down (assuming the numbers being
rounded tend to be positive.)
http://msdn.microsoft.com/en-us/library/system.math.round.aspx
Since Silverlight doesn't support the MidpointRounding option you have to write your own. Something like:
public double RoundCorrect(double d, int decimals)
{
double multiplier = Math.Pow(10, decimals);
if (d < 0)
multiplier *= -1;
return Math.Floor((d * multiplier) + 0.5) / multiplier;
}
For the examples including how to use this as an extension see the post: .NET and Silverlight Rounding
I had this problem where my SQL server rounds up 0.5 to 1 while my C# application didn't. So you would see two different results.
Here's an implementation with int/long. This is how Java rounds.
int roundedNumber = (int)Math.Floor(d + 0.5);
It's probably the most efficient method you could think of as well.
If you want to keep it a double and use decimal precision , then it's really just a matter of using exponents of 10 based on how many decimal places.
public double getRounding(double number, int decimalPoints)
{
double decimalPowerOfTen = Math.Pow(10, decimalPoints);
return Math.Floor(number * decimalPowerOfTen + 0.5)/ decimalPowerOfTen;
}
You can input a negative decimal for decimal points and it's word fine as well.
getRounding(239, -2) = 200
Silverlight doesn't support the MidpointRounding option.
Here's an extension method for Silverlight that adds the MidpointRounding enum:
public enum MidpointRounding
{
ToEven,
AwayFromZero
}
public static class DecimalExtensions
{
public static decimal Round(this decimal d, MidpointRounding mode)
{
return d.Round(0, mode);
}
/// <summary>
/// Rounds using arithmetic (5 rounds up) symmetrical (up is away from zero) rounding
/// </summary>
/// <param name="d">A Decimal number to be rounded.</param>
/// <param name="decimals">The number of significant fractional digits (precision) in the return value.</param>
/// <returns>The number nearest d with precision equal to decimals. If d is halfway between two numbers, then the nearest whole number away from zero is returned.</returns>
public static decimal Round(this decimal d, int decimals, MidpointRounding mode)
{
if ( mode == MidpointRounding.ToEven )
{
return decimal.Round(d, decimals);
}
else
{
decimal factor = Convert.ToDecimal(Math.Pow(10, decimals));
int sign = Math.Sign(d);
return Decimal.Truncate(d * factor + 0.5m * sign) / factor;
}
}
}
Source: http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/
Simple way is:
Math.Ceiling(decimal.Parse(yourNumber + ""));
Rounding numbers with .NET has the answer you are looking for.
Basically this is what it says:
Return Value
The number nearest value with precision equal to digits. If value is halfway between two numbers, one of which is even and the other odd, then the even number is returned. If the precision of value is less than digits, then value is returned unchanged.
The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called rounding to nearest, or banker's rounding. If digits is zero, this kind of rounding is sometimes called rounding toward zero.
using a custom rounding
public int Round(double value)
{
double decimalpoints = Math.Abs(value - Math.Floor(value));
if (decimalpoints > 0.5)
return (int)Math.Round(value);
else
return (int)Math.Floor(value);
}
Here's the way i had to work it around :
Public Function Round(number As Double, dec As Integer) As Double
Dim decimalPowerOfTen = Math.Pow(10, dec)
If CInt(number * decimalPowerOfTen) = Math.Round(number * decimalPowerOfTen, 2) Then
Return Math.Round(number, 2, MidpointRounding.AwayFromZero)
Else
Return CInt(number * decimalPowerOfTen + 0.5) / 100
End If
End Function
Trying with 1.905 with 2 decimals will give 1.91 as expected but Math.Round(1.905,2,MidpointRounding.AwayFromZero) gives 1.90! Math.Round method is absolutely inconsistent and unusable for most of the basics problems programmers may encounter. I have to check if (int) 1.905 * decimalPowerOfTen = Math.Round(number * decimalPowerOfTen, 2) cause i don not want to round up what should be round down.
This is ugly as all hell, but always produces correct arithmetic rounding.
public double ArithRound(double number,int places){
string numberFormat = "###.";
numberFormat = numberFormat.PadRight(numberFormat.Length + places, '#');
return double.Parse(number.ToString(numberFormat));
}

Scala Has Infinity but no Infinitesimal. Why?

Open a Scala interpreter.
scala> 1E-200 * 1E-200
res1: Double = 0.0
scala> 1E200 * 1E200
res2: Double = Infinity
A very large product value evaluates to Infinity.
A very small value evaluates to zero.
Why not be symmetrical and create something called Infinitesimal?
Basically this has to do with the way floating point numbers work, which has more to do with your processor than scala. The small number is going to be so small that the closest representation corresponds to +0 (positive zero), and so it underflows to 0.0. The large number is going to overflow past any valid representation and be replaced with +inf (positive infinity). Remember that floating point numbers are a fixed precision estimation. If you want a system that is more exact, you can use http://www.scala-lang.org/api/2.11.8/#scala.math.BigDecimal
Scala, just like Java, follows the IEEE specification for floating point numbers, which does not have "infinitesimals". I'm not quite sure infinitesimals would make much sense either way, as they have no mathematical interpretation as numbers.

TI Basic Numeric Standard

Are numeric variables following a documented standard on TI calculators ?
I've been really surprised noticing on my TI 83 Premium CE that this test actually returns true (i.e. 1) :
0.1 -> X
0.1 -> Y
0.01 -> Z
X*Y=Z
I was expecting this to fail, assuming my calculator would use something like IEEE 754 standard to represent floating points numbers.
On the other hand, calculating 2^50+3-2^50 returns 0, showing that large integers seems use such a standard : we see here the big number has a limited mantissa.
TI-BASIC's = is a tolerant comparison
Try 1+10^-12=1 on your calculator. Those numbers aren't represented equally (1+10^-12-1 gives 1E-12), but you'll notice the comparison returns true: that's because = has a certain amount of tolerance. AFAICT from testing on my calculator, if the numbers are equal when rounded to ten significant digits, = will return true.
Secondarily,
TI-BASIC uses a proprietary BCD float format
TI floats are a BCD format that is nine bytes long, with one byte for sign and auxilliary information and 14 digits (7 bytes) of precision. The ninth byte is used for extra precision so numbers can be rounded properly.
See a source linked to by #doynax here for more information.

How doubles truncate in swift in case of overflow

I know that swift's Double values have 15 decimal point precision so I took a variable
let pi: Double = 3.1415926535897932384
and REPL returned me
pi: Double = 3.1415926535897931
One thing I can clearly see that REPL has rounded off 32384 to 31(in case of overflow). So, is it following the standard mathematics rule for rounding off or something else.
This behavior has to do how floating point digits are represented in binary. So the conversion to binary doesn't round to the next decimal representation instead it converts it to the next binary one.
// test this in a playground
9.05 // returns 9.050000000000001
You shouldn't consider the last digit of a double value in general.

mod() operation weird behavior

I use mod() to compare if a number's 0.01 digit is 2 or not.
if mod(5.02*100, 10) == 2
...
end
The result is mod(5.02*100, 10) = 2 returns 0;
However, if I use mod(1.02*100, 10) = 2 or mod(20.02*100, 10) = 2, it returns 1.
The result of mod(5.02*100, 10) - 2 is
ans =
-5.6843e-14
Could it be possible that this is a bug for matlab?
The version I used is R2013a. version 8.1.0
This is not a bug in MATLAB. It is a limitation of floating point arithmetic and conversion between binary and decimal numbers. Even a simple decimal number such as 0.1 has cannot be exactly represented as a binary floating point number with finite precision.
Computer floating point arithmetic is typically not exact. Although we are used to dealing with numbers in decimal format (base10), computers store and process numbers in binary format (base2). The IEEE standard for double precision floating point representation (see http://en.wikipedia.org/wiki/Double-precision_floating-point_format, what MATLAB uses) specifies the use of 64 bits to represent a binary number. 1 bit is used for the sign, 52 bits are used for the mantissa (the actual digits of the number), and 11 bits are used for the exponent and its sign (which specifies where the decimal place goes).
When you enter a number into MATLAB, it is immediately converted to binary representation for all manipulations and arithmetic and then converted back to decimal for display and output.
Here's what happens in your example:
Convert to binary (keeping only up to 52 digits):
5.02 => 1.01000001010001111010111000010100011110101110000101e2
100 => 1.1001e6
10 => 1.01e3
2 => 1.0e1
Perform multiplication:
1.01000001010001111010111000010100011110101110000101 e2
x 1.1001 e6
--------------------------------------------------------------
0.000101000001010001111010111000010100011110101110000101
0.101000001010001111010111000010100011110101110000101
+ 1.01000001010001111010111000010100011110101110000101
-------------------------------------------------------------
1.111101011111111111111111111111111111111111111111111101e8
Cutting off at 52 digits gives 1.111101011111111111111111111111111111111111111111111e8
Note that this is not the same as 1.11110110e8 which would be 502.
Perform modulo operation: (there may actually be additional error here depending on what algorithm is used within the mod() function)
mod( 1.111101011111111111111111111111111111111111111111111e8, 1.01e3) = 1.111111111111111111111111111111111111111111100000000e0
The error is exactly -2-44 which is -5.6843x10-14. The conversion between decimal and binary and the rounding due to finite precision have caused a small error. In some cases, you get lucky and rounding errors cancel out and you might still get the 'right' answer which is why you got what you expect for mod(1.02*100, 10), but In general, you cannot rely on this.
To use mod() correctly to test the particular digit of a number, use round() to round it to the nearest whole number and compensate for floating point error.
mod(round(5.02*100), 10) == 2
What you're encountering is a floating point error or artifact, like the commenters say. This is not a Matlab bug; it's just how floating point values work. You'd get the same results in C or Java. Floating point values are "approximate" types, so exact equality comparisons using == without some rounding or tolerance are prone to error.
>> isequal(1.02*100, 102)
ans =
1
>> isequal(5.02*100, 502)
ans =
0
It's not the case that 5.02 is the only number this happens for; several around 0 are affected. Here's an example that picks out several of them.
x = 1.02:1000.02;
ix = mod(x .* 100, 10) ~= 2;
disp(x(ix))
To understand the details of what's going on here (and in many other situations you'll encounter working with floats), have a read through the Wikipedia entry for "floating point", or my favorite article on it, "What Every Computer Scientist Should Know About Floating-Point Arithmetic". (That title is hyperbole; this article goes deep and I don't understand half of it. But it's a great resource.) This stuff is particularly relevant to Matlab because Matlab does everything in floating point by default.