4 ms·
Yes. But then you write that at the boundary. Along with the other consistency checks. And you are forced to think about it at the appropriate time, instead of
by SolarNet 10y ago
Yes. But then you write that at the boundary. Along with the other consistency checks. And you are forced to think about it at the appropriate time, instead of forgetting about it entirely (floats) or introducing subtle errors (integers, and then likely casting it to a float to calculate 1% and then adding it back by casting back to an integer; hint: that's also a bad idea because it has floats in it - which as we've learned recently on HN - are not that deterministic or precise).
- mikeash 10y agoLet's say you're not a complete idiot and avoid the use of floats altogether, what subtle errors would you avoid by using arbitrary precision numbers over integers?
- SolarNet 10y agoWell first riddle me this. How do you calculate a ⅓% (1 / 3 of a percent) fee with integers. Depending on your choice of solution I can tell you how it has a problem and how arbitrary precision numbers would solve it.
- mikeash 10y agoI'd do: fee = amount / 300 More generally: represent the percentage as a rational number, then multiply the amount by the numerator and then divide by the denominator.
- danbruc 10y agoWith integers this will rounds towards zero. It may be that you only wanted to charge a fee of 1 for an amount of 599 but it would not be unreasonable to want to charge a fee of 2 in this case. Which you could of course fix by adding 299 or maybe 150 before the devision but that makes some pretty hard to understand code.
- mikeash 10y agoYou can wrap up the logic for doing a division with floor, ceiling, or whatever rounding in a function so you don't get ugly and error prone stuff at each call site. If you wanted your fees to round up then the actual code would look something like: fee = round_up_multiply(amount, 1, 300)
- danbruc 10y agoDo you see how you will end up reimplementing a fixed point decimal number type?
- mikeash 10y agoOf course. An integer that represents a number of some subdivision of your nominal "one" unit is a fixed-point decimal number type. They're two names for the same thing. But the other commenter was discussing arbitrary precision arithmetic libraries, not fixed-point decimals.
- danbruc 10y agoOf course. An integer that represents a number of some subdivision of your nominal "one" unit is a fixed-point decimal number type. They're two names for the same thing. And an array of single precision floats is a zero-terminated UTF-8 encoded string. Using an actual fixed point decimal number type is still preferable over going straight to the underlying integer, even if it is only for the easier to read source code with decimal points where they belong instead of having to perform the transformation in your head while reading. But the other commenter was discussing arbitrary precision arithmetic libraries, not fixed-point decimals. Fair point.
- mikeash 10y agoI take your point, but the nitpicker in me (some might say there's nothing else in there) wants to point out that an array of floats is highly unlikely to be valid UTF-8. If your language of choice has a good fixed-point decimal library, or you can switch to one that does, then I agree that would definitely be the superior solution.
- danbruc 10y agoThat is something I would be interested in, I always assumed arbitrary precision arithmetics would also have to turn one third into some finite approximation, though you can choose however much precision you need or want. I ran across this once when I implemented a rational number type with arbitrary precision integers and wanted to print the decimal representation. I wanted to determine the repeating and non-repeating fractional parts but failed to find any applicable math or algorithm. If I am not misremembering and did not do my research to poorly, this is an open problem and at best you can start expanding and look if you return to a state you were in before. But at some point you have to give up because you can not event determine the length of the repeating and non-repeating fractional parts in advance and even some relatively small numerators and denominators can produce some pretty long decimal representations until they start repeating.