Search code examples
swifttrigonometry

Trigonometry Function (cos) Returning Different Value to a Calculator


When I use the cos function on a calculator cos(0) = 1, cos(90) = 0 cos(180) = -1 and cos(270) = 0. However I don't know how to produce these results in my code. The result I receive in my code are either 1 or -1, but never 0. Below is what I have try and none give me the same results as a calculator, what am I missing?

print(cos(0))               // receiver error "Ambiguous use of 'cos'"
print(cos(90))              // receiver error "Ambiguous use of 'cos'"
print(cos(180))             // receiver error "Ambiguous use of 'cos'"
print(cos(270))             // receiver error "Ambiguous use of 'cos'"

print(cos(M_PI*0))          // returns 1
print(cos(M_PI*1))          // returns -1
print(cos(M_PI*2))          // returns 1
print(cos(M_PI*3))          // returns -1

print(cos(M_PI*0))          // returns 1
print(cos(M_PI*90))         // returns 1
print(cos(M_PI*180))        // returns 1
print(cos(M_PI*270))        // returns 1

print(cos(M_PI/M_PI-1))     // returns 1
print(cos(M_PI/M_PI+89))    // returns -0.44
print(cos(M_PI/M_PI+179))   // returns -0.59
print(cos(M_PI/M_PI+269))   // reutnrs 0.98

The below repeats through the results of 1, 0, -1, 0:

var x: Double = 0
while x < 100 {
    print(Int(cos(M_PI*(x*0.5))))
    x = x + 1
} 

Solution

  • The Darwin trig functions work in Radians.

    Issue 1.1

    print(cos(0))               // receiver error "Ambiguous use of 'cos'"
    print(cos(90))              // receiver error "Ambiguous use of 'cos'"
    print(cos(180))             // receiver error "Ambiguous use of 'cos'"
    print(cos(270))             // receiver error "Ambiguous use of 'cos'"
    

    These are ambiguous because there are two version of cos, which these two types:

    • (Double) -> Double
    • (Float) -> Float

    Both Double and Float conform to ExpressibleByIntegerLiteral, so both can be expressed by an Int. It's ambiguous as to which of the two types the Int should express.

    If you want the Double version, you can call it with:

    • cos(0 as Double)
    • cos(0.0) because direct use of a floatliteral as a Double takes precedence over a conversion via expressiblebyfloatliteral.

    If you want the Float version, you can call it with: cos(0 as Float)

    In both cases, the ambiguity can be resolved if context provides sufficient information. For example:

    functionThatTakesADouble(cos(0)) // will use the `(Double) -> Double` version
    functionThatTakesAFloat(cos(0)) // will use the `(Float) -> Float` version
    print(cos(M_PI*0)) // M_PI is a Double, so 0 is treated as a Double
    

    Issue 1.2

    After resolving the type ambiguity, like so:

    print(cos(0.0))   // 1.0
    print(cos(90.0))  // -0.44807361612917
    print(cos(180.0)) // -0.598460069057858
    print(cos(270.0)) // 0.984381950632505
    

    We get correct answers. Remember, the system trig functions work in radians.

    Issue 2

    print(cos(M_PI*0))          // returns 1
    print(cos(M_PI*1))          // returns -1
    print(cos(M_PI*2))          // returns 1
    print(cos(M_PI*3))          // returns -1
    

    These are all correct values.

    Issue 3

    print(cos(M_PI*0))          // returns 1
    print(cos(M_PI*90))         // returns 1
    print(cos(M_PI*180))        // returns 1
    print(cos(M_PI*270))        // returns 1
    

    These are also correct. cos is 1 for every even multiple of pi radians.

    Issue 4

    print(cos(M_PI/M_PI-1))     // returns 1
    print(cos(M_PI/M_PI+89))    // returns -0.44
    print(cos(M_PI/M_PI+179))   // returns -0.59
    print(cos(M_PI/M_PI+269))   // reutnrs 0.98
    

    M_PI/M_PI is 1.0 (as a Double), so these cases are equivalent to the first, but with the extra type information necessary to allow the compiler to unambiguously choose (Double) -> Double cos over (Float) -> Float.