I will never understand float point arithmetic…

```
julia> a = 10000 * 7 /100
700.0
julia> b = 10000 * 0.07
700.0000000000001
julia> c = 1000 * 0.69999999999999999
700.0
```

(but at list I am aware of the danger…)

I will never understand float point arithmetic…

```
julia> a = 10000 * 7 /100
700.0
julia> b = 10000 * 0.07
700.0000000000001
julia> c = 1000 * 0.69999999999999999
700.0
```

(but at list I am aware of the danger…)

3 Likes

As we say in France: “un homme averti en vaut 1.999999999999999”

(Literally, the saying says something like “a forewarned person is worth two”)

11 Likes

Also, I’m not sure you were really looking for an explanation, but maybe it will help to note that:

```
julia> 7/100
0.07
```

So this is merely an example of non-associativity of the floating-point operations:

```
julia> 10000 * (7 / 100)
700.0000000000001
julia> (10000 * 7) / 100
700.0
```

4 Likes

Look at this excellent presentation by Avik Sengupta

5 Likes

Part of the confusion is that, although this is *printed* as `0.07`

, it’s actually a slightly different number. (Binary) floating-point values are **integers times powers of two**, so 7/100 is not exactly representable and has to be rounded to:

```
julia> big(7/100)
0.070000000000000006661338147750939242541790008544921875
```

When you realize that a rounding operation has already occurred here, then the fact that multiplying this by `10000`

results in something different from `700`

is not so surprising. In contrast, when you compute `10000 * 7 / 100`

it is parsed as `(10000 * 7) / 100`

, and each of *these* operations can be performed *exactly* (the result of each operation is an integer value) so there is no rounding (even if you write `1e4 * 7 / 100`

so that the first multiplication is done in floating point).

The reason that `7/100`

prints as `0.07`

is tricky — printing floating-point values in decimal has a long history, and basically all of computer science has coalesced around the principle that you should print the *shortest* decimal number that *rounds to the same value* when converted back to floating point. (`0.07`

will print the same way in Python, C, …)

12 Likes

It’s not so hard to understand floating-point arithmetic, actually! Trefethen and Bau’s book “Numerical Linear Algebra” covers the essentials in a couple lectures (each 4 or 5 pages of text). It’ll change your reaction to the above from “Wha…?” to “Yep, that’s how it works, no mystery about it.” Well worth reading.

6 Likes

What is the rule here, is for a / b, when both a and b (or at least b) is an integer (or non-approx), *and the result should be*, then you get exact, i.e. integer?

About “it is parsed as `(10000 * 7) / 100”, for constants, is it allowed to parse as 7 * (10000 / 100)"; e.g. if 7 had been not a constant?

If you want that calculation, I recommend to use rational number representation:

```
julia> 10000*7//100
700//1
```

To complement a bit, IEEE754 Float64 are stored as M × 2^{E}, where M is the 53-bit integer mantissa and E the 11-bit exponent (some further details omitted).

700.0 becomes M=700 and E=0, as integer values between and

-2^52 and 2^52-1 are stored with E=0.

0.07 becomes M=6157265115545601 and E=-43, in terms of bits very different from an integer value.

BTW, is there a package for Julia that would reveal mantissa and exponent of IEEE754 floats?

Yes. The result of each elementary fp operation (`+,-,*,/`

) is *as if* you had done that operation exactly and *then* rounded to the closest representable value. This means that if the exact result is representable, it will be returned exactly.

4 Likes

There are built-in functions: How to get the significand and the exponent of a floating point number?

3 Likes

No.

slightly more specifically, no unless you use `@fastmath`

1 Like

If you dislike this, then try the very nice `DecFP.jl`

package, which implements the IEEE 754-2008 decimal floating point standard (`Dec32`

, `Dec64`

, and `Dec128`

types).

There are some cases dealing with currencies where using decimal floating point may even be required (at least at one point, by EU directive).

As an example, if you are calculating a 5% sales tax on a $0.70 candy bar, if you use binary floating point arithmetic, you get 3 cents, but with decimal arithmetic, it will be 4 cents (and the government will want that extra cent, to be sure, and it can add up!)

4 Likes

…fantastic example…

More specifically, fastmath doesn’t change how it is *parsed*, but can allow the compiler to re-associate fp expressions.

3 Likes

Ha! Please look at my only message on this forum, with three likes by the way! But keep in mind, in fact, I don’t fully understand either, but I hope that when it comes down to it, I’ll turn to this lesson and definitely understand!

1 Like