I would recommend against using decimal floating-point unless you really must. On almost any hardware you're likely to use, binary floating-point arithmetic will be an order of magnitude faster than decimal floating-point arithmetic. Moreover, if you use decimal floating-point, you will chronically find yourself unable to use standard numerical libraries without converting your data first.
Instead, I would strongly recommend learning a bit about how binary floating-point works. The basic fact you need to know is that the Float64 type can only represent real values of the form: n*2^k where |n| < 2^53 and -1074 ≤ k ≤ 971 (both integers). Some basic but potentially unintuitive facts that follow from this: 1. Only rational values whose denominators are powers of two can be represented as binary floating-point values exactly. Most rational numbers are not of this form, of course. When you write `0.1` in Julia (and most programming languages), it does not mean 1/10. Instead, it means the number of the above form that is closest to 1/10, namely: 3602879701896397*2.0^-55 = 0.1000000000000000055511151231257827021181583404541015625. This value is printed as "0.1" by convention since that's the shortest decimal input that gives you this value, and therefore in some sense the most likely way to input it. However, there are many other decimal inputs that produce the same Float64 value, such as 0.0999999999999999987 and 0.10000000000000001. 2. Unlike rational numbers, which are dense in all intervals of the real number line, floating-point values are not at all dense: there is a gap between each floating-point value and the next representable value. The eps(x) function gives the distance to the next representable value: eps(1.0) = 2.220446049250313e-16 eps(12.34) = 1.7763568394002505e-15 eps(1e25) = 2.147483648e9. The gap between moderately sized values like 1.0 and 12.34 is very small, but the gaps between large numbers like 1e25 is very large. In general, the gap between values of size 10^n is around 10^(n-16). That is because Float64s have 53 bits of precision and log10(2^53) ≈ 16. On Mon, Dec 28, 2015 at 8:38 AM, Scott Jones <[email protected]> wrote: > That is simply because you are using binary floating point (Float64 in > Julia), instead of decimal floating point. There is a very nice package, > DecFP.jl, (kudos to Steven Johnson, @stevengj on GitHub), that wraps the > Intel decimal arithmetic library. > You can do `Pkg.add("DecFP") ; using DecFP` (you may get a lot of > deprecation warnings, esp. on v0.5, you can also do a > `Pkg.checkout("DecFP") ; Pkg.build("DecFP")` to eliminate all but one > warning on v0.5), and then you can do: > > julia> a = d"0.2" > +2E-1 > > julia> for i in 1:10 ; println(a * i) ; end > +2E-1 > +4E-1 > +6E-1 > +8E-1 > +10E-1 > +12E-1 > +14E-1 > +16E-1 > +18E-1 > +20E-1 > > The output is a bit funny, but the answers are exact, unlike most of the > answers in the binary floating point case you showed. > > Note: the most heavily used language in the world (at least up to the > early 2000s, I'm not sure what the stats would be like now), which was the > 2nd ANSI standardized language, Cobol, > originally only had decimal arithmetic (Modern Cobols also support IEEE > binary floating point). > A number of other heavily used (but not much talked about) languages, such > as M/MUMPS, which happened to be the 3rd language standardized by ANSI, > even before ANSI C. > The most used version of M/MUMPS these days is Caché ObjectScript - which > adds many things, including objects and IEEE binary floats. > The Pick/MultiValue family of database languages also use decimal floating > point. > > There is now the IEEE 754-2008 standard for decimal floating point, which > the DecFP.jl package conforms to (implementing 3 of the formats - there are > some more formats which I'm trying to write a package for, which are also > implemented in hardware on IBM POWER architecture processors). > > There are a number of cases where it really is better to use decimal > arithmetic, in order to not get in trouble with the tax man! (Lots of > currency operations have this same issue) > Here's a real simple example: you have a store, where you sell something > for 70 cents, and there is a 5% sales tax. How much do tax to you charge > the customer? > > *julia>tax = * >> *.7 * 0.05* >> *0.034999999999999996**julia> * >> *round(tax,2)* >> *0.03**julia> tax = * >> *d".70" * d"0.05"* >> *+350E-4**julia> * >> *round(tax,2)**+4E-2* > > > As you can see, with binary floating point, you get the wrong answer > (0.03), but with decimal floating point, you get the correct answer (the > one the tax authorities will want you to give them). > > Depending on your particular use case, you can either use the default IEEE > binary floating point numbers in Julia, or the DecFP.jl package. > > Scott > > On Monday, December 28, 2015 at 4:59:24 AM UTC-5, Yonghee Kim wrote: >> >> I wrote simple code like this >> >> ---------------------- >> a = 0.2 >> >> for i in 1:10 >> println(a * i) >> end >> --------------------------- >> >> >> and what I got is not 0.2, 0.4, 0.6, 0.8, 1.0 .... >> >> but this. >> >> 0.2 >> 0.4 >> 0.6000000000000001 >> 0.8 >> 1.0 >> 1.2000000000000002 >> 1.4000000000000001 >> 1.6 >> 1.8 >> 2.0 >> >> >> >> println(0.2 * 3) does the same thing. not 0.6 but 0.6000000000000001 >> >> does anyone know why this happens? >> >>
