4 ms·
Or use a language with arbitrary precision numbers (they are only like 50 years old so I can see why many people don't use them /s). As someone else already poi
by SolarNet 10y ago
Or use a language with arbitrary precision numbers (they are only like 50 years old so I can see why many people don't use them /s). As someone else already pointed out, this still prevents calculations of fees as a percentage, and other issues.
- waqf 10y agoC'mon, the Egyptians had arbitrary precision numbers.
- mikeash 10y agoDon't you still have to be smart about rounding at some point? Otherwise compounding a (say) 1% fee will lead to arbitrarily long numbers.
- SolarNet 10y agoYes. 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.
- j_s 10y agoI believe there are libraries to do this that can be used in any language. http://speleotrove.com/decimal/ http://speleotrove.com/decimal/ etc. https://hn.algolia.com/?query=speleotrove&sort=byDate&dateRange=all&type=comment https://hn.algolia.com/?query=speleotrove&sort=byDate&dateRa...
- SolarNet 10y agoInstructions unclear booted left-pad (if a developer is stupid enough to use floats for money, I doubt they are aware of how library systems work).
- MichaelBurge 10y agoArbitrary precision rationals increase in storage and processing time each time you multiply them, so they open you up to DoS attacks. My order of preference: * Fixed-point arithmetic: All-around safe, though you'll probably need to take a maintenance window later if you need extra precision. * Floating point arithmetic: Sounds dangerous, but you can eliminate most of the risk using database checks. * Arbitrary-precision arithmetic: Almost any place they're used opens you up to DoS attacks; it's very difficult to detect the problem. I'd ensure my database and application server have debugging symbols installed, replace libgmp with something that alerts by generating core dumps when a timing threshold is passed, use a language where backtraces are easy to read in gdb, and ensure that all arbitrary-precision arithmetic is written against gmp. I'm not sure what I'd do when I detected the problem though: If I truncated 1 + 1/(10^10)! to 1 to resolve the issue, it's equivalent to using floating point in the first place.
- SolarNet 10y ago> Arbitrary precision rationals increase in storage and processing time each time you multiply them Only if you store the arbitrary precision number. Last I checked you can't actually have a tenth of a cent, so it has to be rounded at some point. Like when you store it. I was advocating calculation be done with arbitrary precision numbers which do not have this problem. > Fixed-point arithmetic This is a decent solution as long as you have enough precision and a strategy for detecting lost cents. > Floating point arithmetic Which is non-deterministic based off of optimization level and hardware. Waits for the bank to switch to a new cluster and watch all of their numbers change for the lols. No wonder banks don't know how much money they have.