2

I need a loop to increase the number by 3rd decimal and the print should look like this

1.1 1.101 1.102 1.103 ... 2.0 2.001 2.002 ... 2.1 2.101 ... for ($i = 1.1; $i <= 3; $i += .001){ echo $i . '<br />'; } 

the start seems to be ok but somewhere along the loop the decimal number becomes to big

1.54 1.541 1.542 1.543 1.544 1.545 1.546 1.547 1.548 1.549 1.55 1.551 1.552 1.553 1.554 1.5549999999999 1.5559999999999 1.5569999999999 1.5579999999999 1.5589999999999 

And if I use

number_format($i,3) 

all my numbers have 3 decimal points like

1.100 and I need it to be 1.1 .

What am I missing ?

2
  • This has something to do with how floating point numbers are stored in PHP link Commented Mar 29, 2015 at 18:38
  • 1
    @MatejŽvan That issue is not php specific, it is a general effect of floating point arithmetic. Commented Mar 29, 2015 at 18:45

4 Answers 4

2

Have a read about floating point numbers. Basically, not all decimal numbers can be precisely represented in floating points.

Try rounding the number:

for ($i = 1.1; $i <= 3; $i += .001){ echo round($i,3) . '<br />'; } 
Sign up to request clarification or add additional context in comments.

Comments

1

Live demo

Try rounding the values and store them in $i:

for ($i = 1.1; $i <= 3; $i += .001){ $i = round($i, 3); echo $i . '<br />'; } 

Comments

1

This should work for you:

(Here I just use sprintf() and specify that it should display a double (lf -> long float) to the 3rd decimal point)

echo sprintf("%.3lf", $i) . '<br />'; 

If you wonder why you get this results see: Is floating point math broken?

BTW: This method also has the side effect, that it displays: 1.560 instead of 1.56

Comments

1

This is an effect of how floating point arithmetic works. That can lead to poor precision. The issue is that the error in computation adds up. So rounding alone is not really safe in general. Its safety depends in the number of additions done, so on the number of iterations here...

Have a try like that instead:

for ($i = 1100; $i <= 3000; $i++) { echo $i/1000 . "<br>\n"; } 

The above uses integer computation instead, the following division does not lead to added up errors.

5 Comments

@button Sure it does, give it a try. Why shouldn't it?
it is actually right on the money but I dont see why round would be different in this case? can you collaborate ?
As said: the error adds up with the iterations (OK, that is simplified, but still true). Just rounding the output is unsafe. What would work would be to round the sums, so something like for ($i = 1.1; $i <= 3; $i = round($i+.001,3)). Because the max error per iteration is guaranteed to be lower than the iteration. But that would be much slower... The above is easier and faster.
@Benn Sorry, forgot to ping you. See above: ^^^
understand now , but for my use ( I use it for em line height ) the round seems to be ok and precise enough. if this was bigger iteration I would go with your solution. thank you for the info

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.