Сделать Swift Предполагать градусы для расчетов тригонометрии

Можно ли изменить параметр, свойство и т.д. в Swift для iOS, чтобы он принимал градусы для расчетов тригонометрии, а не радиан?

Например, sin(90) будет оцениваться как 1.

У меня есть:

let pi = 3.14 
var r2d = 180.0/pi
var d2r = pi/180

... но конверсии действительно задействованы для некоторых длинных триггерных уравнений.

Ответ 1

Как уже говорилось в других ответах, в стандартной библиотеке нет тригонометрических функций, которые принимают аргументы в градусах.

Если вы определяете свою собственную функцию, вы можете использовать __sinpi(), __cospi() и т.д. вместо умножения на π:

// 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)
}

Из справочной страницы __sinpi (выделено мной):

__sinpi() функция возвращает синус pi times x (измеряется в радиан). Это можно вычислить более точно, чем sin (M_PI * x), поскольку он может неявно использовать столько битов pi, сколько необходимо для      доставляют результат с округлым результатом, а не 53 бит, к которым M_PI ограничен. При больших x это может      также эффективнее, поскольку сокращение аргумента значительно проще.

__sinpi(), а связанные функции нестандартны, но  доступный на iOS 7/OS X 10.9 и более поздних версиях.

Пример:

sin(degrees: 180.0)       // 0

дает точный результат, в отличие от:

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

И просто для удовольствия: так вы можете определить синусоидальную функцию для всех типов с плавающей запятой, включая CGFloat с перегрузка функции (теперь обновлена ​​для 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))
}

В последнем варианте компилятор автоматически выводит из фактический тип degrees.native, который функционирует для вызова, так что это корректно работает как на 32-битной, так и на 64-разрядной платформах.

Ответ 2

Добавление расширения, чтобы четко определить тип значения, было бы подходящим способом для решения такой задачи:

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 }
}

Поиграйте на игровой площадке и посмотрите, как вы получите ожидаемые результаты:

sin(90.degrees)  --> 1.0
1.㎭  -->  57.2957795130823
1.㎭.degrees --> 1.0
(M_PI / 3).㎭  -->  60.0

Ответ 3

Вы можете определить глобальные функции, которые возвращают грех значения градуса. Просто поместите функцию в быстрый файл вне любого класса.

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

Поэтому в любом месте вашего проекта вы можете просто использовать:

sind(90) // Returns 1

Ответ 4

Там нет настройки или свойства для изменения встроенных тригонометрических функций. Вы должны просто работать строго в радианах, если хотите упростить выражения или определить свой собственный sindeg, cosdeg и т.д.

Каждый из типов с плавающей точкой имеет встроенный static член с именем pi, значение которого является наилучшим приближением к π. Например: Double.pi, Float.pi, CGFloat.pi.

Кроме того, грех 90˚ равен 1, а не 0.

Ответ 5

Это работает на детской площадке и обеспечивает безопасную реализацию степеней/радиан. Определения типов свободно берутся из здесь в списке рассылки Swift evolution с несколькими незначительными исправлениями синтаксиса. Я написал в некоторых функциях триггера; остальные - прямое продолжение того, что я показал.

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)

Ответ 6

Я не совсем уверен, почему вы хотите перегрузить глобальный метод по умолчанию, но если вам нужно, вы можете предоставить альтернативную подпись метода:

func sin(#degrees: Double) -> Double { // Require a parameter name for method call
    let radians: Double = degrees * (M_PI / 180) // Convert to rad
    return sin(radians) // Return result of default method call with automatic conversion
}

sin(degrees: 90) // 1.0
sin(degrees: 180) // 0.0

Тем не менее, это действительно странный способ сделать это, и было бы более целесообразно явно определить свой собственный метод (для чего они предназначены) аналогичным образом:

func sinFromDegrees(degrees: Double) -> Double {
    let radians: Double = degrees * (M_PI / 180)
    return sin(radians)
}

sinFromDegrees(90) // 1.0
sinFromDegrees(180) // 0.0

Ответ 7

Видя, как я много использую триггер. Я нашел лучший способ определить некоторые функции вне class ViewController.

Если вы определяете их в любом из ваших файлов .swift чуть ниже imports и чуть выше class ViewController:UIViewController { }, вы можете вызывать их на протяжении всего проекта.

Итак, для функции sin я назвал ее sindeg() для "градусов греха".

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

Итак, это число ваших степеней преобразует его, решает его и возвращает как градусы. Итак, все, что вам нужно сделать, это тип sindeg(45.5), и результат будет = 0.71325045.

Вот остальные:

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 здесь очень похож, только различие - это формула return

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

Это только для преобразования значения радиана в градусы. Принимает радианы, преобразует, возвращает назад градусы.

func Convert(radians: Double) -> Double {
    return radians * 180.0 / M_PI
}