Оператор піднесення ступенів у Swift


81

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

Невже в мові немає заздалегідь визначеного цілочисельного або плаваючого оператора піднесення до степені?


У моєму випадку це спрацювало як рішення: stackoverflow.com/a/28710112/2161007
Найяр

Відповіді:


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

Краще використовувати **, щоб ви могли використовувати його на ints і не конфліктувати з 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
Омегаман

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
звуковий сигнал

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

це здається ... неефективним
сам-ш

4

Свіфт 4.2

import Foundation

var n = 2.0 // decimal
var result = 5 * pow(n, 2)
print(result)
// 20.0


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.