Swift中的“sign”函数

idfiyjo8  于 2023-05-05  发布在  Swift
关注(0)|答案(8)|浏览(172)

Swift中是否有一个函数,对正数返回+1,对负数返回-1?
我浏览了一个 enormous 文件,如果你在一个典型的函数上右键单击-〉definitions,就会出现这个文件,但是如果它在那里,我不知道它的名字。
我这样做了:

(num < 0 ? -1 : 1)

但如果有内置函数的话,我宁愿使用内置函数--至少是出于自我文档化的原因。

bjp0bcyl

bjp0bcyl1#

Swift 4

正如@Wil Shipley的Swift 4回答中已经指出的那样,现在有一个sign property in the FloatingPoint protocol

FloatingPointSign

浮点值的符号。

  • 枚举案例 *
  • case minus负值的符号。
  • case plus正值的符号。
    然而FloatingPoint源代码中对sign蓝图的注解包含重要信息(尚未?)不存在于生成的文档中:
/// The sign of the floating-point value.
///
/// The `sign` property is `.minus` if the value's signbit is set, and
/// `.plus` otherwise. For example:
///
///     let x = -33.375
///     // x.sign == .minus
///
/// Do not use this property to check whether a floating point value is
/// negative. For a value `x`, the comparison `x.sign == .minus` is not
/// necessarily the same as `x < 0`. In particular, `x.sign == .minus` if
/// `x` is -0, and while `x < 0` is always `false` if `x` is NaN, `x.sign`
/// could be either `.plus` or `.minus`.

强调,"....minus如果值的符号位设置为”“不要使用此属性来检查浮点值是否为负”
总结:使用FloatingPoint协议的新sign属性来实际检查值的signbit是否已设置,但如果试图使用此属性来判断数字是否为负数,请务必小心。

var f: Float = 0.0

if case .minus = (-f).sign { print("A. f is negative!") }

f = -Float.nan

if f < 0 { print("B. f is negative!") }
if case .minus = f.sign { print("C. f is negative!") }

// A. f is negative!
// C. f is negative!

Swift 3

W.r.t.内置函数,我认为最接近的是Foundation方法copysign(_: Double, _: Double) -> Double

let foo = -15.2
let sign = copysign(1.0, foo) // -1.0 (Double)

当然,如果你不是在Double类型的数字上操作,就需要一些类型转换。
但是,我认为没有理由不创建适合您需要的扩展,特别是对于像sign这样简单的函数,因为它们不需要变得臃肿,例如。

extension IntegerType {
    func sign() -> Int {
        return (self < 0 ? -1 : 1)
    }
    /* or, use signature: func sign() -> Self */
}

extension FloatingPointType {
    func sign() -> Int {
        return (self < Self(0) ? -1 : 1)
    }
}

(here也为0生成1,如您问题中的示例所示)。

  • (请根据您的评论进行编辑)*

上述问题的另一种解决方案是使用sign()的默认实现来定义自己的协议,以便符合此协议的所有类型都可以访问该sign()方法。

protocol Signable {
    init()
    func <(lhs:Self, rhs:Self) -> Bool
}

extension Signable {
    func sign() -> Int {
        return (self < Self() ? -1 : 1)
    }
}

/* extend signed integer types to Signable */
extension Int: Signable { }    // already have < and init() functions, OK
extension Int8 : Signable { }  // ...
extension Int16 : Signable { }
extension Int32 : Signable { }
extension Int64 : Signable { }

/* extend floating point types to Signable */
extension Double : Signable { }
extension Float : Signable { }
extension CGFloat : Signable { }

/* example usage */
let foo = -4.2
let bar = 42

foo.sign() // -1 (Int)
bar.sign() // 1  (Int)
velaa5lx

velaa5lx2#

simd库有一个sign方法:

import simd

sign(-100.0) // returns -1
sign(100.0) // returns 1
sign(0.0) // returns 0

如果您使用import SpriteKit,您可以免费获得simd

vjrehmav

vjrehmav3#

在Swift中,floats有一个新的属性:

public var sign: FloatingPointSign { get }

(然而,这只检查符号位,所以它会在某些情况下失败,如-0-请参阅上面接受的答案。

zqdjd7g9

zqdjd7g94#

如果你的值是一个整数,你可以使用signum()。
https://developer.apple.com/documentation/swift/int/2886673-signum
这里有一个代码片段来说明这一点;

let negative: Int = -10
let zero: Int = 0
let positive: Int = 10

print(negative.signum()) // prints "-1"
print(zero.signum()) // prints "0"
print(positive.signum()) // prints "1"
jbose2ul

jbose2ul5#

用途:

let result = signbit(number)

这将为负数返回1,为正数返回0。

let number = -1.0
print("\(signbit(number))")

1

let number = 1.0
print("\(signbit(number))")

0
sg3maiej

sg3maiej6#

FloatingPointType有一个内置的计算变量,但它返回一个布尔值。如果你只需要对浮点数进行这个操作,你可以使用这样的扩展:

extension FloatingPointType {
    var signValue: Int {
        return isSignMinus ? -1 : 1
    }
}

但是,我认为最好的方法是扩展SignedNumberType协议。

extension SignedNumberType {
    var signValue: Int {
        return (self >= -self) ? 1 : -1
    }
}

如果你想让0返回-1,只需将>=改为>
测试用例:

print(3.0.signValue)
print(0.signValue)
print(-3.0.signValue)
olqngx59

olqngx597#

由于copysign不能在Integer上使用,所以我使用这个扩展:

extension Comparable where Self: SignedNumber {

    var sign: Int {
        guard self != -self else {
            return 0
        }
        return self > -self ? 1 : -1
    } 
}
c86crjj0

c86crjj08#

真实世界的、可工作的代码库、随处可见的方法。

不管怎样...
我见过的每个真实世界的应用程序代码库,在实用程序文件中都有这样的东西。
我添加的注解块充分解释了我的想法。

extension CGFloat {
    
    ///Precisely as it says, return a CGFloat "one, signed". Return the sign of
    ///the number, expressed as either +1 or -1. As everyone knows, never use
    ///`.sign` in a working codebase, ever, for any reason, as it's broken by
    ///being stupidly-named. As everyone knows, never use `.signum` in a working
    ///codebase, ever, for any reason, as it's broken by being stupidly-named.
    var oneSigned: CGFloat {
        return (self < 0.0) ? -1.0 : 1.0
    }
}

不要忘记那些没有自我记录的代码:坏了不能用了
所有代码中的每个变量名,更不用说调用名,都必须是绝对不可误解的。
永远不应该有这样的情况,即使是团队中的一个程序员,在一瞬间也必须思考“这是做什么的”,当你处理算法中统一错误的常见来源时,这是非常正确的。
事实上,正如在某个地方的评论中提到的,我经常看到这样的情况:

extension CGFloat {
        var oneSignedCGFloat: CGFloat {
            return (self < 0.0) ? -1.0 : 1.0
        }
    }
extension Float {
        var oneSignedFloat: Float {
            return (self < 0.0) ? -1.0 : 1.0
        }
    }

......所以在类型方面绝对没有错误的可能性。
在极少数情况下,您需要在算法中使用三进制(无论如何,这基本上意味着您的算法考虑不周),我会将其命名为EXTREMELY,例如

extension CGFloat {
        var minusOneZeroOrOneBeAwareThisIsTernary: CGFloat {
            return ... -1, 0 or 1
        }
    }

FWIW。

相关问题