Swift Compound Arithmetic Operation Error

Swift compound arithmetic operation ERROR

The full error message can be found in the Build log in the Report Navigator:


main.swift:15:66: error: cannot invoke '+' with an argument list of type '($T24, $T31)'
var ret = -100.0 + (2.0 * 1.3) + (3.0 * 4.0) + (0.2 * 2.0 * 2.0) + 0.1 * 2.0 * 3.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
main.swift:15:66: note: expression was too complex to be solved in reasonable time;
consider breaking up the expression into distinct sub-expressions
var ret = -100.0 + (2.0 * 1.3) + (3.0 * 4.0) + (0.2 * 2.0 * 2.0) + 0.1 * 2.0 * 3.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~

So yes, this expression is too complex for the current (beta 6) Swift compiler.
I would suggest to file a bug report.

At present, the only workaround seems to be to split the expression in two parts,
e.g.

var ret = -100.0 + (2.0 * 1.3) + (3.0 * 4.0)
ret += (0.2 * 2.0 * 2.0) + 0.1 * 2.0 * 3.0

Of course the parentheses are not necessary here, but removing them does not solve
the problem with the original expression.

Strange Swift numbers type casting

Yes, I also found this quite surprising. Double conforms to both FloatLiteralConvertible and IntegerLiteralConvertible (ExpressibleByFloatLiteral and ExpressibleByIntegerLiteral in Swift 3). Therefore a
Double can be initialized with floating point literal

let a = 3.0

or with an integer literal:

let b : Double = 10

(The same is true for other floating point types like Float and
CGFloat.)

Now it might be unexpected for all of us with an (Objective-)C background
that both statements

let x : Double = 10/4     // x = 2.5 .  Really? Yes!
let y = 10/4 as Double // Same here ...

assign the value 0.25 to the variable. From the context, the result of the
division must be a Double and Swift does not implicitly convert types.
Therefore / must be the floating point division operator

func /(lhs: Double, rhs: Double) -> Double

so the compiler creates both arguments as Doubles from the literals
"10" and "4". (If 10/4 were treated as the division of two integers
then the result would also be an integer, and that cannot be assigned
to a Double.)

Note that this is different from

let z = Double(10/4)   // z = 2.0 . (I just thought that I understood it &%$!?)

which does an integer division and converts the result to Double.
Double has an init(_ v: Int) constructor, and therefore 10/4
can be treated as the division of two integers here.

It really looks a bit strange if we summarize these results:

let x : Double = 10/4     // x = 2.5 
let y = 10/4 as Double // y = 2.5
let z = Double(10/4) // z = 2.0

Now we can apply these results to your expression

(10 / 3.0) - (10 / 3)

The first part (10 / 3.0) can only be a Double, therefore -
must be the floating point subtraction operator

func -(lhs: Double, rhs: Double) -> Double

and thus (10 / 3) must also be a Double. Again, / must be the floating point division operator, so 10 and 3 are treated as Double constants.

Therefore the expression is equivalent to

(Double(10) / 3.0) - (Double(10) / Double(3))

and evaluates to 0.0. If you change the expression to

(10 / 3.0) - Double(10 / 3)

then the result is 0.333... because in this context, 10 / 3
is the division of two integer constants, as explained above.

Swift Math Operations on small Float Values

The Swift Floating-Point Number documentation states:

Note

Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. In situations where either type would be appropriate, Double is preferred.

In this case, it looks like the error is on the order of 4.060564999999999e-09 in each subtraction, based on the amount left over after 200 subtractions. Indeed changing Float to Double reduces the precision such that the loop runs until i = 0.00499999999999918 when it should be 0.005.

That is all well and good, however we still have the problem of construction a loop that will run until i becomes zero. If the amount that you reduce i by remains constant throughout the loop, one only slightly unfortunate work around is:

var x: Double = 1
let reduction = 0.005

for var i = Int(x/reduction); i >= 0; i -= 1, x = Double(i) * reduction {
println(x)
}

In this case your error won't compound since we are using an integer to index how many reductions we need to reach the current x, and thus is independent of the length of the loop.

Swift: initializer 'init(_:)' requires that 'Decimal' conform to 'BinaryInteger'

It would be easier to use the Double func pow(_: Double, _: Double) -> Double instead of using Decimal func pow(_ x: Decimal, _ y: Int) -> Decimal considering that you want to return a Double:

@discardableResult
func calculateAmount() -> Double {
amount = p * pow(1 + (r / Double(n)), Double(n) * Double(t))
return amount
}

Why is there no need to explicitly cast in case of integers?

If you look at the JLS 4.2.2 Integer Operations, it states that the result of a numerical operation between two integral operands is an int or a long. Since there's no implicit cast from an int to byte or a short, you need an explicit cast.

Casting to a type held in a variable

Swift (currently) requires the Type assignment at compile time. You can do some things like this, but you will need to write a converter for each type combination you want to use, e.g:

func convertType(from item: Int) -> Float {
return Float(item)
}

var item: Float = convertType(from: 1)

I would caution going down this road and try and get used to Swift's way of doing things. If you absolutely need it you should be able to use some generic functions with a protocol like FloatConvertable to handle this more simply.



Related Topics



Leave a reply



Submit