5 ms·
Things get a lot easier when you're working with tools that help you out, even just a little. Clojure here, FWIW: (+ 0.1M 0.2M) => 0.3M That 'M' suffix denot
by cemerick 16y ago
Things get a lot easier when you're working with tools that help you out, even just a little.
Clojure here, FWIW:
(+ 0.1M 0.2M) =>
0.3M
That 'M' suffix denotes a BigDecimal, which provides for arbitrary-precision decimal math (which Clojure's arithmetic ops dispatch to as necessary).
A similar 'N' suffix is coming in the next release that denotes (contagious) BigInteger math (though as fast as longs when values are < 2^31), so one doesn't have to worry about overflow issues (which rate up there with misunderstandings of internal floating point representations in terms of frequency).
Other reader syntax is provided for other common notations (e.g. 10e6, 16rFF, 0xFF, 0220, 2r100010101).
- heresy 16y agoThis seems like the right way to do it. Though, I assume non-suffixed literals are still regular floats?
- masklinn 16y ago> This seems like the right way to do it. It's also slow as molasses, which is why very few languages default to decimal floats and use IEEE floats (or doubles) instead, via their hardware implementation. The behavior of IEEE floats and doubles is very well defined, and though they are unfit in some sectors (you do not want to count money using them), have to be massaged a bit when displayed and don't deal well with great differences in powers-of-10 (e.g. 1e21 + 1 == 1e21) they work well enough in practice. And they're implemented in hardware.
- heresy 16y agoI'm aware of the performance hit, I just like the approach of a BigDecimal literal instead of having to write that boilerplate.
- masklinn 16y ago> I just like the approach of a BigDecimal literal instead of having to write that boilerplate. Ah yes. Well not all languages require a bunch of boilerplate either. In Python for instance, there is a type decimal.Decimal which you can just alias to `d` and write: val = d('0.1')
- gxti 16y agoI do wish there were a syntax for Decimal literals, e.g. 0.1D (analogous to 100L as long, etc.). Maybe I'll make it my weekend project even if I don't really expect it to be accepted into CPython proper.
- tonyarkles 16y agoI'm pretty sure the L syntax has gone away in Python3, with numbers being auto-promoted to Long if they're going to overflow. I'm a bit hazy about this, but I think I talked to the maintainer over lunch at PyCon two years ago.
- gxti 16y agoThere's actually no externally-visible long type at all in Python 3, it's all done transparently now. That said, I'm not using Python 3. The promoting behavior you speak of is how Python 2 works.
- masklinn 16y agoIndeed it has, integers and longs have been unified as a single `int` type, so the external marker is gone as well.
- gtani 16y agoI remember reading that Java has one difference from IEEE754 that might bite somebody once in a while: floating point modulo. But I can't find a reference Seems like other delta's (e.g. how many NaN's are implemented) don't much matter. http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html http://java.sun.com/docs/books/jvms/second_edition/html/Conc...
- cemerick 16y agoYes; insofar as maximal perf is a desirable default characteristic, `0.2` must continue to be a regular decimal value (technically, a double in Clojure). We've already been down the path of having to extensively hint Clojure code to get the best perf, and we'll likely not revisit that. That said, the above notation makes advice to those who are having trouble a lot easier.
- roder 16y agoErlang likewise: 1> 0.1 + 0.3. 0.4
- masklinn 16y agoNope, Erlang's floats are still IEEE754 floats: 1> 1.0e21 + 1 == 1.0e21. true
- silentbicycle 16y agoRight. It has arbitrary-precision ints, but lossy floats.
- francoisdevlin 16y agoJust be careful to not use BigDecimal when you really should be using an int (e.g. currency).
- pbiggar 16y agoWhy would you use an int for currency? Isn't that what BigDecimal is for?
- aidenn0 16y agoHistorically finance is done with integer multiples of some fraction of the currency. This allows for easy balancing of both sides of any transaction without things getting too out-of-hand. It's common to see $0.001 as the minimal unit in the US, for example. If you used a decimal fractional representation instead, then one transaction of higher precision would contaminate all accounts it touches, making printing exact balances a pain.
- jluxenberg 16y agoSo, we lop off some precision and call it correct because displaying extra decimal places would be a "pain?" Not sure I'm following your logic here; if my balance is $10.0000005, wouldn't it be wrong to change that to $10.000? If you want to do this correctly, then there should never be a balance that has an amount under the minimal unit. Then it doesn't matter if you use a BigDecimal or an int.
- pbiggar 16y agoTalk me through this. As I understood it, and I must be wrong here, a decimal type is an abstraction around an infinite-precision integer, which represents something like thousandths of a cent? I thought there was an IEEE standard, and it was the standard for all financial transactions. Is this not what BigDecimal is?