Как получить мощность некоторого целого числа в языке Swift?
Я учусь swift в последнее время, но у меня есть основная проблема, которая не может найти ответ
Я хочу получить что-то вроде
var a:Int = 3
var b:Int = 3
println( pow(a,b) ) // 27
но функция pow может работать только с двойным числом, она не работает с целым числом, и я даже не могу привести int к удвоению чем-то вроде Double(a) или A.double()...
почему он не обеспечивает мощность целого числа? он определенно вернет целое число без двусмысленности ! и почему я не могу бросить целое в двойной? он просто меняет 3 на 3.0 (или 3.00000... все равно)
если я получил два целого числа, и я хочу сделать операцию питания, как я могу сделать это гладко?
спасибо!
15 ответов:
если хотите, вы можете объявить
infix
operator
сделать это.// Put this at file level anywhere in your project infix operator ^^ { associativity left precedence 160 } func ^^ (radix: Int, power: Int) -> Int { return Int(pow(Double(radix), Double(power))) } // ... // Then you can do this... let i = 2 ^^ 3 // ... or println("2³ = \(2 ^^ 3)") // Prints 2³ = 8
я использовал две каретки, так что вы все еще можете использовать оператор XOR.
обновление для Swift 3
в Swift 3 "магическое число"
precedence
заменить наprecedencegroups
:precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence } infix operator ^^ : PowerPrecedence func ^^ (radix: Int, power: Int) -> Int { return Int(pow(Double(radix), Double(power))) } // ... // Then you can do this... let i2 = 2 ^^ 3 // ... or print("2³ = \(2 ^^ 3)") // Prints 2³ = 8
кроме того, что ваши объявления переменных имеют синтаксические ошибки, это работает именно так, как вы ожидали. Все, что вам нужно сделать, это привести к удвоению и передать значения в pow. Затем, если вы работаете с 2 Ints, и вы хотите, чтобы Int вернулся на другую сторону операции, просто вернитесь к int
import Darwin let a: Int = 3 let b: Int = 3 let x: Int = Int(pow(Double(a),Double(b)))
иногда, литье
Int
доDouble
не является жизнеспособным решением. При некоторых значениях происходит потеря точности в этом преобразовании. Например, следующий код не возвращает то, что вы могли бы ожидать интуитивно. (Swift 3.0)Double(Int.max - 1) < Double(Int.max) // false!
Если вам нужно точность при больших значениях и не нужно беспокоиться о отрицательные показатели - который вообще не может быть решен с целыми числами в любом случае-тогда эта реализация хвост-рекурсивный алгоритм возведения в степень по квадрату это ваш лучший ставку. Согласно это так ответ, это "стандартный метод для модульного возведения в степень огромных чисел в асимметричной криптографии."
func pow(_ base: Int, _ power: Int) -> Int { func expBySq(_ y: Int, _ x: Int, _ n: Int) -> Int { precondition(n >= 0) if n == 0 { return y } else if n == 1 { return y * x } else if n % 2 == 0 { return expBySq(y, x * x, n / 2) } else { // n is odd return expBySq(y * x, x * x, (n - 1) / 2) } } return expBySq(1, base, power) }
немного подробнее
infix operator ^^ { associativity left precedence 160 } func ^^ (radix: Int, power: Int) -> Int { return Int(pow(CGFloat(radix), CGFloat(power))) }
Если вы не склонны к перегрузке оператора (хотя
^^
решение, вероятно, ясно для кого-то, кто читает ваш код) вы можете сделать быструю реализацию:let pwrInt:(Int,Int)->Int = { a,b in return Int(pow(Double(a),Double(b))) } pwrInt(3,4) // 81
объединение ответов в перегруженный набор функций (и использование "* * "вместо"^^", как некоторые другие языки используют-яснее для меня):
// http://stackoverflow.com/questions/24196689/how-to-get-the-power-of-some-integer-in-swift-language // Put this at file level anywhere in your project infix operator ** { associativity left precedence 160 } func ** (radix: Double, power: Double) -> Double { return pow(radix, power) } func ** (radix: Int, power: Int ) -> Double { return pow(Double(radix), Double(power)) } func ** (radix: Float, power: Float ) -> Double { return pow(Double(radix), Double(power)) }
при использовании Float вы можете потерять точность. Если вы используете числовые литералы и смесь целых и нецелых чисел, по умолчанию вы получите Double. Мне лично нравится возможность использовать математическое выражение вместо функции, такой как pow(a, b), по стилистическим/читабельным причинам, но это только я.
любой операторы, которые заставят pow () выдавать ошибку, также заставят эти функции выдавать ошибку, поэтому бремя проверки ошибок все равно лежит на коде, использующем функцию power. ПОЦЕЛУЙ, ИМХО.
использование собственной функции pow () позволяет, например, взять квадратные корни (2 ** 0,5) или обратные (2 ** -3 = 1/8). Из-за возможности использовать обратные или дробные показатели, я написал весь свой код, чтобы вернуть двойной тип функции pow() по умолчанию, который должен возвращать больше всего точность (если я правильно помню документацию). При необходимости это может быть приведено к типу Int или Float или что-то еще, возможно, с потерей точности.
2 ** -3 = 0.125 2 ** 0.5 = 1.4142135623731 2 ** 3 = 8
mklbtz правильно о возведении в степень путем возведения в квадрат является стандартным алгоритмом для вычисления целочисленных степеней, но хвост-рекурсивная реализация алгоритма кажется немного запутанной. См.http://www.programminglogic.com/fast-exponentiation-algorithms/ для нерекурсивной реализации возведения в степень путем возведения в квадрат в C. я попытался перевести его на Swift здесь:
func expo(_ base: Int, _ power: Int) -> Int { var result = 1 while (power != 0){ if (power%2 == 1){ result *= base } power /= 2 base *= base } return result }
конечно, это можно было бы придумать, создав перегруженный оператор чтобы вызвать его, и он может быть переписан, чтобы сделать его более общим, чтобы он работал над всем, что реализовало
IntegerType
протокол. Чтобы сделать его общим, я бы, вероятно, начал с чего-то вродеfunc expo<T:IntegerType>(_ base: T, _ power: T) -> T { var result : T = 1
но это, вероятно, увлекается.
Если вы действительно хотите реализацию "Int only" и не хотите принуждать к/от
Double
, вам нужно будет реализовать его. Вот тривиальная реализация; есть более быстрые алгоритмы, но это будет работать:func pow (base:Int, power:UInt) -> Int { var answer : Int = 1 for _ in 0..power { answer *= base } return answer } > pow (2, 4) $R3: Int = 16 > pow (2, 8) $R4: Int = 256 > pow (3,3) $R5: Int = 27
в реальной реализации вы, вероятно, захотите проверить некоторые ошибки.
получается, вы также можете использовать
pow()
. Например, вы можете использовать следующее для выражения от 10 до 9.pow(10, 9)
вместе с
pow
,powf()
возвращает afloat
вместоdouble
. Я только проверил это на Swift 4 и macOS 10.13.
пытаясь объединить перегрузку, я попытался использовать дженерики, но не смог заставить его работать. Я, наконец, решил использовать NSNumber вместо того, чтобы пытаться перегрузить или использовать дженерики. Это упрощает следующее:
typealias Dbl = Double // Shorter form infix operator ** {associativity left precedence 160} func ** (lhs: NSNumber, rhs: NSNumber) -> Dbl {return pow(Dbl(lhs), Dbl(rhs))}
следующий код является той же функцией, что и выше, но реализует проверку ошибок, чтобы увидеть, если параметры могут быть преобразованы в удвоения успешно.
func ** (lhs: NSNumber, rhs: NSNumber) -> Dbl { // Added (probably unnecessary) check that the numbers converted to Doubles if (Dbl(lhs) ?? Dbl.NaN) != Dbl.NaN && (Dbl(rhs) ?? Dbl.NaN) != Dbl.NaN { return pow(Dbl(lhs), Dbl(rhs)) } else { return Double.NaN } }
Swift 4.X версии
precedencegroup ExponentiationPrecedence { associativity: right higherThan: MultiplicationPrecedence } infix operator ^^: ExponentiationPrecedence public func ^^ (radix: Float, power: Float) -> Float { return pow((radix), (power)) } public func ^^ (radix: Double, power: Double) -> Double { return pow((radix), (power)) } public func ^^ (radix: Int, power: Int) -> Int { return NSDecimalNumber(decimal: pow(Decimal(radix), power)).intValue }