0

I'm using float value in my project. when I try to access in Project, it's expanding to 1/billions decimal but when it comes to playground it works perfectly.

In xcodeproj:

let sampleFloat: Float = 0.025
print(sampleFloat)  // It prints 0.0250000004

In Playground:

let sampleFloat: Float = 0.025
print(sampleFloat)  // It prints 0.025

Any clue what's happening here? how can I avoid expansion in xcodeproj?

M090009
  • 1,129
  • 11
  • 20
Pandurang Yachwad
  • 1,695
  • 1
  • 19
  • 29
  • What version of Xcode/Swift are you using? I get **`0.025`** from an iOS project build with Xcode 8.3.3. Anyway, if you want a specifically rounded output from `Float`, better use `NumberFormatter`. Output from `print` is not well-defined and may change in a future version of Swift. – OOPer Jul 13 '17 at 21:54
  • I'm using XCode 8.3.3 and I'm getting same result as 0.0250000004 even for the calculations. – Pandurang Yachwad Jul 13 '17 at 21:56
  • An odd behavior, which suggests you should not rely on the output from `print`. By the way, what do you mean by _even for the calculations_ ? – OOPer Jul 13 '17 at 22:00
  • Indeed, it's odd! when I try to use sampleFloat variables in the calculation, it's using 0.0250000004 value instead of 0.025. – Pandurang Yachwad Jul 13 '17 at 22:01
  • In binary floating point system, decimal value `0.025` cannot be represented precisely. Its actual value is rounded to a nearest binary value. The decimal `0.0250000004` may be nearer to the actual binary value than `0.025`. – OOPer Jul 13 '17 at 22:05
  • true, but how I can use 0.025 as 0.025 as when I do calculation it's creating some odd corner cases where all calculations go haywire – Pandurang Yachwad Jul 13 '17 at 22:07
  • Use `NSDecimalNumber`, (aka `Decimal` in Swift). It relies solely on integers to do the math. – allenh Jul 13 '17 at 22:08
  • Or `Decimal` in Swift, if you want calculation results expected from decimal representation of numbers. – OOPer Jul 13 '17 at 22:09
  • It would be helpful if you could you give a sample – Pandurang Yachwad Jul 13 '17 at 22:11
  • Change the type `Float` to `Decimal` in your code. You can use usual operators like `+`, `-` or `*` for `Decimal`. – OOPer Jul 13 '17 at 22:13
  • One addition, conversion from Floating Point Literal to `Decimal` sometimes generate unexpected values, you'd better write it as `Decimal(string: "0.025")!` for fractional values. – OOPer Jul 13 '17 at 22:17
  • Sure, I'll try. Thank you – Pandurang Yachwad Jul 13 '17 at 22:18
  • As explained above, 0.25 can't be precisely expressed in decimal number, so the rounding is expected at print(). If you want to avoid small fractional part (= ....004) then, you need to specify fractional digits: print(String(format: "%.4f", sampleFloat)). See [this](https://stackoverflow.com/questions/40648479/invalid-float-value-swift-3-ios/40649201#40649201) thread, too. – beshio Jul 13 '17 at 23:20
  • in my comment above, 0.25 ==> 0.025. it was a typo. – beshio Jul 13 '17 at 23:38

1 Answers1

1

Lots of comments, but nobody's posted all the info as an answer yet.

The answer is that internally, floating point numbers are represented with binary powers of 2.

In base 10, the tenths digit represents how many 1/10ths are in the value. The hundredths digit represents how many 1/100ths are in the value, the thousandths digit represents how many 1/1000ths are in the value, and so on. In base 10, you can't represent 1/3 exactly. That is 0.33333333333333333...

In binary floating point, the first fractional binary digit represents how many 1/2s are in the value. The second digit represents how many 1/4ths are in in th value, the next digit represents how many 1/8ths are in the value, and so on. There are some (lots of) decimal values that can't be represented exactly in binary floating point. The value 0.1 (1/10) is one such value. That will be approximated by something like 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192.

The value 0.025 is another value that can't be represented exactly in binary floating point.

There is an alternate number format, NSDecimalNumber (Decimal in Swift 3) that uses decimal digits to represent numbers, so it CAN express any decimal value exactly. (Note that it still can't express a fraction like 1/3 exactly.)

Duncan C
  • 128,072
  • 22
  • 173
  • 272