Оператор возведения в степень в Swift


81

Я не вижу оператора возведения в степень, определенного в базовых арифметических операторах в справочнике по языку Swift.

Действительно ли в языке нет предопределенного оператора возведения в степень целого числа или числа с плавающей запятой?


В моем случае это сработало как решение: stackoverflow.com/a/28710112/2161007
Nayyar

Ответы:


96

Оператора нет, но вы можете использовать функцию pow следующим образом:

return pow(num, power)

Если хотите, вы также можете заставить оператор вызывать функцию pow следующим образом:

infix operator ** { associativity left precedence 170 }

func ** (num: Double, power: Double) -> Double{
    return pow(num, power)
}

2.0**2.0 //4.0

Лучше использовать **, чтобы вы могли использовать его в int и не конфликтовать с XOR.
Кевин

3
Оператор ^ определяется как XOR в Swift.
Константин Коваль

22
Предупреждение! Здесь есть проблема. Например, обычно в языках программирования -2.0**2.0 = -(2.0**2.0) = -4.0. Однако здесь -2.0**2.0 = (-2.0)**2.0 = 4.0это может быть не по назначению и может вызвать довольно неприятную и трудную для отслеживания ошибку.
Дэниел Фаррелл

NSHipster использует аналогичное описание, но с приоритетом 160 для соответствия <<и >>. Различные приоритеты приведут к разной интерпретации кода, поэтому важна стандартизация приоритета для общих операторов. Я не знаю , что лучший стандарт, но дает << 2и ** 2тот же приоритет имеет некоторый смысл. nshipster.com/swift-operators
Omegaman 07

8
Разве возведение в степень не ассоциативно? en.wikipedia.org/wiki/Operator_associativity
vwvan

28

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

let x = 2 << 0    // 2
let y = 2 << 1    // 4
let z = 2 << 7    // 256

Обратите внимание, что значение «мощности» на 1 меньше, чем вы думаете.

Обратите внимание, что это быстрее, чем pow(2.0, 8.0)и позволяет избежать использования двойников.


2
Это хорошо, но на самом деле не отвечает на вопрос.
Крис

1
Меня интересовали степени двойки, поэтому он ответил за меня.
dldnh

@chanceoperation В качестве альтернативы, для 2 в степени n вы можете сдвинуть 1 или 0b00000001 влево на n мест Swift Advanced Operators let x = 0b00000001 << exponent // 2**exponent let x = 1 << 0 // 1 let x = 1 << 2 // 4 let x = 1 << 8 // 256
beepscore

13

Для тех, кто ищет версию **инфиксного оператора для Swift 3 :

precedencegroup ExponentiationPrecedence {
  associativity: right
  higherThan: MultiplicationPrecedence
}

infix operator ** : ExponentiationPrecedence

func ** (_ base: Double, _ exp: Double) -> Double {
  return pow(base, exp)
}

func ** (_ base: Float, _ exp: Float) -> Float {
  return pow(base, exp)
}

2.0 ** 3.0 ** 2.0    // 512
(2.0 ** 3.0) ** 2.0  // 64

5
Ницца. Не забудьте import Darwinполучитьpow
iainH

4
Я уверен, что ассоциативность должна быть левой, а не правой. 2 ^ 3 ^ 2 равно 64, а не 512.
brandonscript

Ну, и в Python, и в JavaScript 2**3**2это 512, а не 64. Я не знаю ни одного языка программирования с левоассоциативным оператором возведения в степень. Все они правильно-ассоциативны. Если вы реализуете это в Swift, вам обязательно следует сделать это правильно-ассоциативным, чтобы соответствовать другим популярным языкам, а также математическим соглашениям .
Ray Toal

5

Сделал так:

operator infix ** { associativity left precedence 200 }

func ** (base: Double, power: Double) -> Double {
    return exp(log(base) * power)
}

это кажется ... неэффективным
sam-w



2

Если вас особенно интересует оператор возведения в степень для Intтипа, я не думаю, что существующие ответы будут особенно хорошо работать для больших чисел из-за того, как числа с плавающей запятой представлены в памяти. При преобразовании в Floatили Doubleиз , Intа затем обратно (что требуется pow, powfи powlфункции в Darwinмодуле) вы можете потерять точность . Вот точная версия для Int:

let pow = { Array(repeating: $0, count: $1).reduce(1, *) }

Обратите внимание, что эта версия не особенно эффективно использует память и оптимизирована для размера исходного кода.

Другая версия, которая не создает промежуточный массив:

func pow(_ x: Int, _ y: Int) -> Int {
  var result = 1
  for i in 0..<y {
    result *= x
  }
  return result
}


0

Альтернативный ответ - использовать NSExpression

let mathExpression = NSExpression(format:"2.5**2.5")
let answer = mathExpression.expressionValue(with: nil, context: nil) as? Double

или же

let mathExpression = NSExpression(format:"2**3")
let answer = mathExpression.expressionValue(with: nil, context: nil) as? Int
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.