Step of DoubleProgression


#1

In the for loop, there are 3 types of step progression as shown here which are Int,
Long and char.

How can I create:

infix fun DoubleProgression.step(step: double): DoubleProgression

So that I can execute my loop below:

for (i in 0..4 step 0.05)


#2

I would take a look at the source of IntRange, IntProgression and IntProgressionIterator.

The “magic” you want is in the IntProgressionIterator.

You would probably want to create a DoubleRange as well as step functions from IntRange and DoubleRange to your new DoubleProgression :slight_smile:


#3

I would recommend you to consider using a for loop with Int or Long, and then adjust the result to the scale you need, instead of using Double in the first place, because floating-point numbers trend to lose precision.

For instance, for (i in 0..4 step 0.05) print("$i, ") would output:

0.0, 0.05, 0.1, 0.15000000000000002, 0.2, 0.25, 0.3, 0.35, 0.39999999999999997, 0.44999999999999996, 0.49999999999999994, 0.5499999999999999, 0.6, 0.65, 0.7000000000000001, 0.7500000000000001, 0.8000000000000002, 0.8500000000000002, 0.9000000000000002, 0.9500000000000003, 1.0000000000000002, 1.0500000000000003, 1.1000000000000003, 1.1500000000000004, 1.2000000000000004, 1.2500000000000004, 1.3000000000000005, 1.3500000000000005, 1.4000000000000006, 1.4500000000000006, 1.5000000000000007, 1.5500000000000007, 1.6000000000000008, 1.6500000000000008, 1.7000000000000008, 1.7500000000000009, 1.800000000000001, 1.850000000000001, 1.900000000000001, 1.950000000000001, 2.000000000000001, 2.0500000000000007, 2.1000000000000005, 2.1500000000000004, 2.2, 2.25, 2.3, 2.3499999999999996, 2.3999999999999995, 2.4499999999999993, 2.499999999999999, 2.549999999999999, 2.5999999999999988, 2.6499999999999986, 2.6999999999999984, 2.7499999999999982, 2.799999999999998, 2.849999999999998, 2.8999999999999977, 2.9499999999999975, 2.9999999999999973, 3.049999999999997, 3.099999999999997, 3.149999999999997, 3.1999999999999966, 3.2499999999999964, 3.2999999999999963, 3.349999999999996, 3.399999999999996, 3.4499999999999957, 3.4999999999999956, 3.5499999999999954, 3.599999999999995, 3.649999999999995, 3.699999999999995, 3.7499999999999947, 3.7999999999999945, 3.8499999999999943, 3.899999999999994, 3.949999999999994, 3.999999999999994,

However, for (i in 0..80 step 1) print("${i / 20.0}, ") outputs:

0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3.0, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, 3.7, 3.75, 3.8, 3.85, 3.9, 3.95, 

It’s up to you to decide which option is the best, but I think it preaty clear.


#4

Thanks, do you have any idea why numbers like 0.15000000000000002 and 0.39999999999999997 are appearing!


#5

It has to do with the way floating point numbers are represented in memory. A double is represented by 8 bytes, therefor there are only 2^64 different numbers that can be represented. The format used by Java and therefor Kotlin is IEE 754.
Basicly if you add 0.05 multiple times, the error accumulates. That’s why you sometimes get these long, strange numbers.
If you use ints and divide them like @SackCastellon suggested you also might not get exactly 0.3 but your are guaranteed to get the closest value.


#6

And if you need to work in exact values for decimal numbers that is what BigDecimal is for.