Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pow returns different results using Double or Decimal with negative exponent

Tags:

ios

swift

With Xcode 11.1 if I run a playground with:

pow(10 as Double, -2)  // 0.01

I get same output using Float:

pow(10 as Float, -2) // 0.01

But if I try to use the pow(Decimal, Int) as in:

pow(10 as Decimal, -2) // NaN

Does anybody know why?

Is there a better way to deal with positive and negative exponent with pow and Decimal? I need Decimal as they behave as I expect with currency value.

EDIT: I know how to resolve that from math perspective, I'd like to understand why it happens and/or if it can be solved without adding on the cyclomatic complexity of my code (e.g. checking if the exponent is negative and executing 1 / pow)

like image 857
The Horny Coder Avatar asked Jan 15 '20 17:01

The Horny Coder


3 Answers

Well, algebraically, x^(-p) == 1/(x^(p))

So, convert your negative power to a positive power, and then take the reciprocal.

1/pow(10 as Decimal, 2) // 0.01
like image 60
Jawad Ali Avatar answered Sep 30 '22 15:09

Jawad Ali


I think that this struct give us an idea about the problem:

public struct Decimal {

    public var _exponent: Int32

    public var _length: UInt32 // length == 0 && isNegative -> NaN

    public var _isNegative: UInt32

    public var _isCompact: UInt32

    public var _reserved: UInt32

    public var _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)

    public init()

    public init(_exponent: Int32, _length: UInt32, _isNegative: UInt32, _isCompact: UInt32, _reserved: UInt32, _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16))
}

The length condition should be satisfacted only length == 0, but as UInt32 doesn't represents fractionary numbers the condition is satisfacted...

like image 21
Carla Camargo Avatar answered Sep 30 '22 15:09

Carla Camargo


That's simply how NSDecimal / NSDecimalNumber works: it doesn't do negative exponents. You can see a rather elaborate workaround described here:

https://stackoverflow.com/a/12095004/341994

As you can see, the workaround is exactly what you've already been told: look to see if the exponent would be negative and, if so, take the inverse of the positive root.

like image 44
matt Avatar answered Sep 30 '22 14:09

matt