What does “% is unavailable: Use truncatingRemainder instead” mean?

后端 未结 5 577
Happy的楠姐
Happy的楠姐 2020-12-12 18:44

I get the following error when using code for an extension, I\'m not sure if they\'re asking to just use a different operator or modify the values in the expression based on

相关标签:
5条回答
  • 2020-12-12 19:07

    The % modulus operator is defined only for integer types. For floating-point types, you need to be more specific about the kind of IEEE 754 division/remainder behavior you want, so you have to call a method: either remainder or truncatingRemainder. (If you're doing floating-point math you actually need to care about this, and lots of other stuff, or you can get unexpected / bad results.)

    If you actually intend to do integer modulus, you need to convert the return value of CMTimeGetSeconds to an integer before using %. (Note that if you do, you'll lop off the fractional seconds... depending on where you're using CMTime that may be important. Do you want minutes:seconds:frames, for example?)

    Depending on how you want to present CMTime values in your UI, it might be better to extract the seconds value and pass it to NSDateFormatter or NSDateComponentsFormatter so you get appropriate locale support.

    0 讨论(0)
  • 2020-12-12 19:11

    There's no need to create a separate modulo operator for floating point numbers, unless you think it makes the code safer. You can overload the % operator to accept floating point numbers like so:

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

    Usage

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

    You can now use % with any two floating point numbers of the same tye.

    0 讨论(0)
  • 2020-12-12 19:15

    I found that the following works in Swift 3:

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

    where totalSeconds is a TimeInterval (Double).

    0 讨论(0)
  • 2020-12-12 19:16

    CMTimeGetSeconds() returns a floating point number (Float64 aka Double). In Swift 2 you could compute the remainder of a floating point division as

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

    In Swift 3 this is done with

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

    Applied to your code:

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

    However, in this particular case it is easier to convert the duration to an integer in the first place:

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

    Then the next lines simplify to

    let hours = totalSeconds / 3600
    let minutes = (totalSeconds % 3600) / 60
    let seconds = totalSeconds % 60
    
    0 讨论(0)
  • 2020-12-12 19:25

    Bring back the simple modulo syntax in swift 3:

    This syntax was actually suggested on Apples official swift mailing list here but for some reason they opted for a less elegant syntax.

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

    This simple swift 3 migration tip is part of a more comprehensive swift 3 migration guide with many insights (35k loc / 8-days of migration) http://eon.codes/blog/2017/01/12/swift-3-migration/

    0 讨论(0)
提交回复
热议问题