Hacker News new | ask | show | jobs
by kmill 3502 days ago
It wouldn't have been a problem if it instead used an index variable i ranging from 0 to the number of sides, computing 2pii/sides along the way.

If you're going to rely on repeated addition of irrational numbers to come out to some exact value, then you've misunderstood the abilities of finite decimal representations. It is something easy to overlook, but shouldn't be too surprising to someone who has computed anything by hand (for instance, try long dividing 1/7 out to some number of decimal places, and then adding the result to itself seven times --- if it's a problem there it's not simply a tooling issue, assuming of course the problem isn't with decimals!).

Though, if we want to fix our tools, perhaps instead of the promise of a "cos" or "sin" functions, we could have (ngon-point i n) which returns [(cos (/ i n)) (sin (/ i n))]. Then you wouldn't be tempted to use floating-point numbers to represent the index of a polygon vertex.

2 comments

I fully agree.

As a more general strategy, just use integers (preferably unsigned integers) for all critical stuff such as state handling and looping over. Then, perform floating point operations only on top of that, as a last step. Sometime you don't even need that and use fixed point arithmetics instead (i.e. change your unit to some fixed fraction, e.g. in accounting calculate with integer cents instead of floating point euros/dollars).

> Then, perform floating point operations only on top of that, as a last step.

Right. "Once you go float, you never go back."

Any time you need discrete operations like counting and equality, do it in integer space. Avoid going from integer space back to floating point space.

We can do better. It's true that decimal representation doesn't work:

    0.999999 = 0.142857 + 0.142857 + 0.142857 + 0.142857 + 0.142857 + 0.142857 + 0.142857 
And yes, rewriting the problem in an integer-indexed form does get the correct result:

    1 = (1 + 1 + 1 + 1 + 1 + 1 + 1) / 7
But what we want, in both the original code and in this example, is to calculate:

        1   1   1   1   1   1   1
    1 = — + — + — + — + — + — + —
        7   7   7   7   7   7   7
That's even hard to type out in our limited format here on HN. But it's what we mean to do.

Maybe better tooling could infer that if the limited math produces an angle indistinguishably close to 2pi, we probably meant for it to be equal to 2pi. Maybe it could do fractional addition, instead of converting to a decimal representation and truncating the number of digits.

Maybe it would write the outputs of the function in the initial triangle example, instead of as

    ([50 0]
     [-24.99999999999999 43.30127018922194]
     [-25.00000000000002 -43.301270189221924])
it would be represented as

    ([50 0]
     [-25 25*sqrt(3)]
     [-25 -25*sqrt(3)])
Because the sine of 2pi/3 is sqrt(3)/2, not 0.866.