在Swift中测试一个十进制数是否为整数

7

使用Swift 3。

我在网上找到了很多奇怪的解决方案,用于检查一个 Decimal 对象是否为整数。所有东西都感觉比必要的复杂得多。

这是我的解决方案:

extension Decimal {
    var isWholeNumber: Bool {
        return self.exponent == 1
    }
}

在我的测试中,这个是有效的。我的问题是,我是否漏掉了一些显而易见的东西?

3
实际上,你希望返回self.exponent >= 0,但除此之外,我想不到为什么它不能工作。 - John Montgomery
谢谢@JohnMontgomery,经过更多的测试,我发现我需要添加更多的检查。这是我的解决方案:return self.isZero || (self.isNormal && self.exponent >= 0) - mgChristopher
1
请注意,当创建一个只有getter没有setter的实例计算属性时,您可以省略get关键字及其括号。例如:var isWholeNumber: Bool { return isZero || (isNormal && exponent >= 0) } - Leo Dabus
2
我看到了@PauloMattos :D。这里有一些我找到的SO帖子123。我曾经想尝试#3中提到的解决方案之一,但仍然感觉比必要的工作还多。 - mgChristopher
1
@mgChristopher: #1 可以在Swift中无问题地进行翻译。它是更多的代码,但有一个优点,它只使用文档记录的函数 - 就我所看到的而言,Decimal的确切表示形式没有任何保证,Objective-C变体 甚至声明“NSDecimal的字段是私有的”。 - Martin R
显示剩余4条评论
4个回答

8

谢谢评论!这是我现在正在使用的。

extension Decimal {
    var isWholeNumber: Bool { 
        return self.isZero || (self.isNormal && self.exponent >= 0) 
    }
}

2
这会给整数值、未归一化的Decimal提供一个错误的负数。 - Alexander
我认为在大多数情况下这个方法可行,但是例如 Decimal(1.00000000000000009).isWholeNumber 返回 true,对于17位数字而言,这里的关键是不要从double转换为Decimal。 - William Hu

5

以下是将Objective-C解决方案翻译成Swift的结果:(参考链接)

extension Decimal {
    var isWholeNumber: Bool {
        if isZero { return true }
        if !isNormal { return false }
        var myself = self
        var rounded = Decimal()
        NSDecimalRound(&rounded, &myself, 0, .plain)
        return self == rounded
    }
}

print(Decimal(string: "1234.0")!.isWholeNumber) // true
print(Decimal(string: "1234.5")!.isWholeNumber) // false

即使尾数不是最小值(或指数不是最大值),例如100 * 10-1,此方法仍然有效。示例:

let z = Decimal(_exponent: -1, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0,
                _mantissa: (100, 0, 0, 0, 0, 0, 0, 0))

print(z) // 10.0
print(z.exponent) // -1
print(z.isWholeNumber) // true

在我看来,在这里使用守卫语句更具有自然的语法:guard !isZeroguard isNormal - Alexander
1
@Alexander:不,我认为在 guard !isZero else { return true } 中使用“双重否定”并不更自然。零必须被单独处理,但它并不是一个“异常情况”。 - Martin R
@MartinR:FWIW,guard 不是用于“异常情况”的。它是用于应该强制退出当前作用域的情况。无论如何,if 和 guard 的使用通常取决于实现者的判断(我会在这里使用 guard,但你的情况可能不同)。感谢您的回答。 - Frizlab
3
@Frizlab说,guard被引入是为了解决“if let金字塔问题”,但可以与任何布尔表达式一起使用。也许我表达不好,我只是反对在每种“提前返回”情况下都使用guard。在这种情况下,“如果是零,则返回真”比“否则,返回真”更容易理解,在我看来 - Martin R

0

我对Swift还很新,但我正在将输入与四舍五入后的输入进行比较:

let input = 2.9

round(input) == input
        3        2.9

-2

我不确定它在所有情况下都能工作,但这可能是一个更简洁的选项

extension Decimal {

    static var decimalSeparator: String { return NumberFormatter().decimalSeparator }

    var isFraction: Bool {
        return self.description.contains(Decimal.decimalSeparator)
    }

    var isWhole: Bool {
        return !isFraction
    }

}

1
将数字转换为字符串,然后在字符串中查找符号是可能解决问题的最慢和资源消耗最大的方式之一。 - user28434'mstep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接