Make Swift Assume Degrees for Trigonometry Calculations

后端 未结 7 2432
抹茶落季
抹茶落季 2020-12-06 14:01

Is it possible to change a setting, property, etc in Swift for iOS so that it assumes degrees for trigonometry calculations rather than radians?

For example si

相关标签:
7条回答
  • 2020-12-06 14:13

    Adding an extension to identify the kind of value clearly would be a appropriate way to handle such a thing:

    import Darwin // needed to get M_PI
    extension Double {
      public var degrees: Double { return self * M_PI / 180 }
      public var ㎭: Double { return self * 180 / M_PI }
    }
    

    Pop that into a playground and see how you get the results you expect:

    sin(90.degrees)  --> 1.0
    1.㎭  -->  57.2957795130823
    1.㎭.degrees --> 1.0
    (M_PI / 3).㎭  -->  60.0
    
    0 讨论(0)
  • 2020-12-06 14:18

    You can define global functions that return the sin of a degree value. Just place the function in a swift file outside of any class.

    func sind(degrees: Double) -> Double {
        return sin(degrees * M_PI / 180.0)
    }
    

    So anywhere in your project you can just use:

    sind(90) // Returns 1
    
    0 讨论(0)
  • 2020-12-06 14:20

    This runs in a playground, and provides a type-safe implementation of degree/radian units. The type definitions are freely taken from here on the Swift evolution mailing list with a couple of minor syntax fixes. I wrote in some of the trig functions; the rest are a straightforward continuation of what I've shown.

    import Cocoa
    
    //MARK:- AngleType    
    protocol AngleType: FloatLiteralConvertible, IntegerLiteralConvertible {
        var value: Double { get set }
    
        init(_ value: Double)
        init(_ value: Int)
        init<T: IntegerType>(integerLiteral value: T)
        init<T: FloatingPointType>(floatLiteral value: T)
    }
    
    
    // Implement FloatLiteralConvertible and IntegerLiteralConvertible
    extension AngleType {
        init<T: IntegerType>(integerLiteral value: T) {
            self.init(value)
        }
    
        init<T: IntegerType>(_ value: T) {
            self.init(integerLiteral: value)
        }
    
        init<T: FloatingPointType>(floatLiteral value: T) {
            self.init(value)
        }
    
        init<T: FloatingPointType>(_ value: T) {
            self.init(floatLiteral: value)
        }
    }
    
    //MARK:- Degree
    struct Degree: AngleType {
        typealias FloatLiteralType = Double
        typealias IntegerLiteralType = Int
    
        var value: Double
    
        init(_ value: Double) {
            self.value = value
        }
    
        init(_ value: Int) {
            self.value = Double(value)
        }
    }
    
    protocol DegreeConvertible {
        init(degreeLiteral value: Degree)
    }
    
    extension Degree: CustomStringConvertible, CustomDebugStringConvertible {
        var description: String {
            return self.value.description
        }
    
        var debugDescription: String {
            return "\(self.value.description)°"
        }
    }
    
    extension Degree: RadianConvertible {
        init(radianLiteral value: Radian) {
            self.value = Double(radianLiteral:value) * 180.0 / M_PI
        }
    
        init(_ value: Radian) {
            self.init(radianLiteral: value)
        }
    }
    
    //MARK:- Radian
    struct Radian: AngleType {
        typealias FloatLiteralType = Double
        typealias IntegerLiteralType = Int
    
        var value: Double
    
        init(_ value: Double) {
            self.value = value
        }
    
        init(_ value: Int) {
            self.value = Double(value)
        }
    }
    
    protocol RadianConvertible {
        init(radianLiteral value: Radian)
    }
    
    extension Radian: CustomStringConvertible, CustomDebugStringConvertible {
        var description: String {
            return self.value.description
        }
    
        var debugDescription: String {
            return "\(self.value.description)㎭"
        }
    }
    
    extension Radian: DegreeConvertible {
        init(degreeLiteral value: Degree) {
            self.value = Double(degreeLiteral: value) * M_PI / 180.0
        }
    
        init(_ value: Degree) {
            self.init(degreeLiteral: value)
        }
    }
    
    //MARK:- Adding Conformance To Built In Types
    extension FloatLiteralType: DegreeConvertible, RadianConvertible {
        init(degreeLiteral degree: Degree) {
            self = degree.value
        }
    
        init(radianLiteral radian: Radian) {
            self = radian.value
        }
    }
    
    extension CGFloat: DegreeConvertible, RadianConvertible {
        init(degreeLiteral degree: Degree) {
            self.init(degree.value)
        }
    
        init(radianLiteral radian: Radian) {
            self.init(radian.value)
        }
    
        init(_ degree: Degree) {
            self.init(degreeLiteral: degree)
        }
    
        init(_ radian: Radian) {
            self.init(radianLiteral: radian)
        }
    }
    
    func sin(value: Radian) -> Double { return sin(Double(value.value)) }
    func asin(value: Double) -> Radian { return Radian(Double(asin(value))) }
    func cos(value: Radian) -> Double{ return cos(Double(value.value)) }
    func acos(value: Double) -> Radian { return Radian(Double(acos(value))) }
    
    
    func sin(value: Degree) -> Double{ return sin(Radian(value)) }
    func asin(value: Double) -> Degree { return Degree(Double(asin(value))) }
    func cos(value: Degree) -> Double{ return cos(Radian(value)) }
    func acos(value: Double) -> Degree { return Degree(Double(acos(value))) }
    
    let d180: Degree = Degree(180.0)
    let r180: Radian = Radian(degreeLiteral: d180)
    
    let d0 = Degree(0.0)
    let r0 = Radian(d0)
    
    let dsin180 = sin(d180)
    let rsin180 = sin(r180)
    let dcos180 = cos(d180)
    let rcos180 = cos(r180)
    
    let dsin0 = sin(d0)
    let rsin0 = sin(r0)
    let dcos0 = cos(d0)
    let rcos0 = cos(r0)
    
    let adsin180: Degree = asin(dsin180)
    let adcos180: Degree = acos(dcos180)
    
    0 讨论(0)
  • 2020-12-06 14:22

    Seeing as I use trig a lot. I found the best way was to define some functions outside of the class ViewController.

    If you define them in any one of your .swift files just below the imports and just above the class ViewController:UIViewController { } then you can call them throughout the whole project.

    So for the sin function, I named it sindeg() standing for "sin degrees".

    func sindeg(degrees: Double) -> Double {
        return sin(degrees * M_PI / 180.0)
        }
    

    So this takes your degrees number converts it, solves it and returns as degrees. So all you need to do is type sindeg(45.5) and the result would = 0.71325045.

    Here is the others:

    func cosdeg(degrees: Double) -> Double {
        return cos(degrees * M_PI / 180.0)
    }
    func tandeg(degrees: Double) -> Double {
        return tan(degrees * M_PI / 180.0)
    }
    

    arcTan here is very similar, only difference is the return formula

     func atanDegree(degrees: Double) -> Double {
            return atan(degrees) * 180 / M_PI
        }
    

    This one is just to convert a radian value to degrees. Takes in radians, converts, returns back degrees.

    func Convert(radians: Double) -> Double {
        return radians * 180.0 / M_PI
    }
    
    0 讨论(0)
  • 2020-12-06 14:29

    There's no setting or property to change the built-in trigonometric functions. You should just work strictly in radians if you want to simplify your expressions, or define your own sindeg, cosdeg, etc.

    Each of the floating-point types has a built-in static member named pi whose value is the best approximation to π. For example: Double.pi, Float.pi, CGFloat.pi.

    Also, sin 90˚ is 1, not 0.

    0 讨论(0)
  • 2020-12-06 14:31

    As already said in the other answers, there are no trigonometric functions in the standard library that take the arguments in degrees.

    If you define your own function then you can use __sinpi(), __cospi(), etc ... instead of multiplying by π:

    // Swift 2:
    func sin(degrees degrees: Double) -> Double {
        return __sinpi(degrees/180.0)
    }
    
    // Swift 3:
    func sin(degrees: Double) -> Double {
        return __sinpi(degrees/180.0)
    }
    

    From the __sinpi manual page (emphasis added):

    The __sinpi() function returns the sine of pi times x (measured in radians). This can be computed more accurately than sin(M_PI * x), because it can implicitly use as many bits of pi as are necessary to deliver a well-rounded result, instead of the 53-bits to which M_PI is limited. For large x it may also be more efficient, as the argument reduction involved is significantly simpler.

    __sinpi() and the related functions are non-standard, but available on iOS 7/OS X 10.9 and later.

    Example:

    sin(degrees: 180.0)       // 0
    

    gives an exact result, in contrast to:

    sin(180.0 * M_PI/180.0) // 1.224646799147353e-16
    

    And just for fun: This is how you can define the degree-based sine function for all floating point types, including CGFloat with function overloading (now updated for Swift 3):

    func sin(degrees: Double) -> Double {
        return __sinpi(degrees/180.0)
    }
    
    func sin(degrees: Float) -> Float {
        return __sinpif(degrees/180.0)
    }
    
    func sin(degrees: CGFloat) -> CGFloat {
        return CGFloat(sin(degrees: degrees.native))
    }
    

    In the last variant, the compiler automatically infers from the actual type of degrees.native which function to call, so that this works correctly on both 32-bit and 64-bit platforms.

    0 讨论(0)
提交回复
热议问题