“%不可用:改为使用truncatingRemainder”是什么意思?


103

使用扩展代码时,出现以下错误,我不确定他们是否要求使用其他运算符或基于Internet搜索修改表达式中的值。

错误:%不可用:改用truncatingRemainder

扩展代码:

extension CMTime {
    var durationText:String {
        let totalSeconds = CMTimeGetSeconds(self)
        let hours:Int = Int(totalSeconds / 3600)
        let minutes:Int = Int(totalSeconds % 3600 / 60)
        let seconds:Int = Int(totalSeconds % 60)

        if hours > 0 {
            return String(format: "%i:%02i:%02i", hours, minutes, seconds)
        } else {
            return String(format: "%02i:%02i", minutes, seconds)
        }
    }
}

设置分钟和秒变量时会发生错误。


1
我认为CMTimeGetSeconds返回浮动
僵尸

3
这意味着%操作员不可用,您应该考虑使用类似truncatingRemainder方法的方法。
马特

1
你不能用模Float64,但上Int只; 因此:let minutes:Int = Int(totalSeconds) % 3600 / 60; let seconds:Int = Int(totalSeconds) % 60是正确的方法。
Holex

Answers:


172

CMTimeGetSeconds()返回浮点数(Float64aka Double)。在Swift 2中,您可以将浮点除法的余数计算为

let rem = 2.5 % 1.1
print(rem) // 0.3

在Swift 3中,这是通过

let rem = 2.5.truncatingRemainder(dividingBy: 1.1)
print(rem) // 0.3

应用于您的代码:

let totalSeconds = CMTimeGetSeconds(self)
let hours = Int(totalSeconds / 3600)
let minutes = Int((totalSeconds.truncatingRemainder(dividingBy: 3600)) / 60)
let seconds = Int(totalSeconds.truncatingRemainder(dividingBy: 60))

但是,在这种特殊情况下,首先更容易将持续时间转换为整数:

let totalSeconds = Int(CMTimeGetSeconds(self)) // Truncate to integer
// Or:
let totalSeconds = lrint(CMTimeGetSeconds(self)) // Round to nearest integer

然后,接下来的几行简化为

let hours = totalSeconds / 3600
let minutes = (totalSeconds % 3600) / 60
let seconds = totalSeconds % 60

24

%模数运算符仅被定义为整数类型。对于浮点类型,您需要更详细地了解所需的IEEE 754除法/余数行为类型,因此必须调用一个方法:remaindertruncatingRemainder。(如果您正在进行浮点数学运算,则实际上您需要关心这一点以及许多其他东西,否则您会得到意想不到的/不好的结果。)

如果您实际上打算做整数模数,则需要CMTimeGetSeconds在使用之前将返回值转换为整数%。(请注意,如果这样做,您将舍弃小数秒...,这取决于您使用的位置CMTime,这可能很重要。例如,您是否想要分钟:秒:帧?)

根据您希望CMTime在UI中呈现值的方式,最好提取秒值并将其传递给NSDateFormatterNSDateComponentsFormatter以便获得适当的语言环境支持。


10

快速带回简单的模语法:

实际上,此语法已在此处的 Apples官方快速邮件列表中建议使用,但由于某些原因,他们选择了不太优雅的语法。

infix operator %%/*<--infix operator is required for custom infix char combos*/
/**
 * Brings back simple modulo syntax (was removed in swift 3)
 * Calculates the remainder of expression1 divided by expression2
 * The sign of the modulo result matches the sign of the dividend (the first number). For example, -4 % 3 and -4 % -3 both evaluate to -1
 * EXAMPLE: 
 * print(12 %% 5)    // 2
 * print(4.3 %% 2.1) // 0.0999999999999996
 * print(4 %% 4)     // 0
 * NOTE: The first print returns 2, rather than 12/5 or 2.4, because the modulo (%) operator returns only the remainder. The second trace returns 0.0999999999999996 instead of the expected 0.1 because of the limitations of floating-point accuracy in binary computing.
 * NOTE: Int's can still use single %
 * NOTE: there is also .remainder which supports returning negatives as oppose to truncatingRemainder (aka the old %) which returns only positive.
 */
public func %% (left:CGFloat, right:CGFloat) -> CGFloat {
    return left.truncatingRemainder(dividingBy: right)
}

这个简单的Swift 3迁移技巧是更全面的Swift 3迁移指南的一部分,该指南具有许多见解(35k Loc / 8天迁移)http://eon.codes/blog/2017/01/12/swift-3-migration /


1
这个A是很好,提供了有趣的信息,同时也试图回答的问题:
的JakubTruhlář

3
@JakubTruhlář...伙计,Thx。IMO这是我最快的3迁移修复程序。不能相信人们会否决它。模数是一个非常重要的概念,并且在每个有算术的代码本中都被认为是模数。使它变得冗长是没有意义的,因为代码中的算术应尽可能紧凑地编写。当您看到完整的图片反对理解各个变量的含义时,随着我们理解算术的认知能力增强。IMO综合变量命名在业务逻辑中很重要,但在算术中并不重要,恰恰相反。
eonist

2
@GitSync Modulo是一个重要的概念,但仅对于整数存在。您应该了解其中的区别。
Sulthan

5
@GitSync模运算仅对整数存在。您正在谈论余数。十进制值具有两种余数类型。因此,Swift决定将操作明确化。在双精度值上计算整数余数(截断余数)不是很常见。
苏珊(Sulthan)

1
@GitSync有remainder(dividingBy:)truncatingRemainder(dividingBy:)。您可能想阅读两者的文档。另外,请参考C ++ stackoverflow.com
6102948/…

2

我发现以下在Swift 3中有效:

    let minutes = Int(floor(totalSeconds / 60))
    let seconds = Int(totalSeconds) % 60

其中totalSecondsTimeIntervalDouble)。


3
混合上下浮动不是一个好主意,例如,totalSeconds = 59.8您的代码计算0分0秒。
Martin R

你是对的。实际上,round根本不需要。
benwiggy

0

除非您认为它使代码更安全,否则无需为浮点数创建单独的模运算符。您可以重载%运算符以接受浮点数,如下所示:

func %<N: BinaryFloatingPoint>(lhs: N, rhs: N) -> N {
    lhs.truncatingRemainder(dividingBy: rhs)
}

用法

let a: Float80 = 10
let b: Float80 = 3
print(a % b)

现在%,您可以使用同一轮胎的任意两个浮点数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.