“% Không khả dụng: Sử dụng truncatingRemainder thay thế” nghĩa là gì?


104

Tôi gặp lỗi sau khi sử dụng mã cho tiện ích mở rộng, tôi không chắc liệu họ có yêu cầu chỉ sử dụng một toán tử khác hay sửa đổi các giá trị trong biểu thức dựa trên tìm kiếm trên internet hay không.

Lỗi:% không khả dụng: Sử dụng truncatingRemainder thay thế

Mã phần mở rộng:

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

(Các) lỗi xảy ra khi thiết lập các biến phút và giây.


1
tôi nghĩ CMTimeGetSeconds trả về float
zombie

3
Nó có nghĩa là %toán tử không khả dụng và bạn nên xem xét sử dụng một cái gì đó như truncatingRemainderphương pháp thay thế.
matt

1
bạn không thể sử dụng modulo trên Float64Intchỉ trên ; do đó: let minutes:Int = Int(totalSeconds) % 3600 / 60; let seconds:Int = Int(totalSeconds) % 60là cách chính xác.
holex

Câu trả lời:


174

CMTimeGetSeconds()trả về một số dấu phẩy động ( Float64hay còn gọi là Double). Trong Swift 2, bạn có thể tính phần còn lại của phép chia dấu phẩy động là

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

Trong Swift 3, điều này được thực hiện với

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

Đã áp dụng cho mã của bạn:

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

Tuy nhiên, trong trường hợp cụ thể này, việc chuyển đổi thời lượng thành số nguyên ngay từ đầu sẽ dễ dàng hơn:

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

Sau đó, các dòng tiếp theo đơn giản hóa thành

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

24

Các %nhà điều hành mô đun được xác định duy nhất đối với các loại nguyên. Đối với kiểu dấu phẩy động, bạn cần phải cụ thể hơn về kiểu hành vi chia / dư IEEE 754 mà bạn muốn, vì vậy bạn phải gọi một phương thức: hoặc remainderhoặc truncatingRemainder. (Nếu bạn đang làm toán dấu phẩy động, bạn thực sự cần quan tâm đến điều này và nhiều thứ khác , nếu không bạn có thể nhận được kết quả không mong muốn / không tốt.)

Nếu bạn thực sự có ý định thực hiện mô-đun số nguyên, bạn cần chuyển đổi giá trị trả về của CMTimeGetSecondsmột số nguyên trước khi sử dụng %. (Lưu ý rằng nếu bạn làm vậy, bạn sẽ bỏ qua số giây phân số ... tùy thuộc vào nơi bạn đang sử dụng CMTime, điều đó có thể quan trọng. Bạn có muốn phút: giây: khung hình không?)

Tùy thuộc vào cách bạn muốn trình bày CMTimecác giá trị trong giao diện người dùng của mình, tốt hơn là trích xuất giá trị giây và chuyển nó đến NSDateFormatterhoặc NSDateComponentsFormatterđể bạn nhận được hỗ trợ ngôn ngữ thích hợp.


10

Mang lại cú pháp modulo đơn giản trong swift 3:

Cú pháp này thực sự đã được đề xuất trong danh sách gửi thư nhanh chính thức của Táo khuyết ở đây nhưng vì một số lý do họ đã chọn một cú pháp kém thanh lịch hơn.

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

Mẹo di chuyển 3 nhanh đơn giản này là một phần của hướng dẫn di chuyển nhanh 3 toàn diện hơn với nhiều thông tin chi tiết (35k loc / 8 ngày di chuyển) http://eon.codes/blog/2017/01/12/swift-3-migration /


1
Câu A này ổn, cung cấp thông tin thú vị và cũng cố gắng trả lời câu hỏi Q.
Jakub Truhlář Ngày

3
@Jakub Truhlář ... Trời ạ, Thx. IMO Đây là bản sửa lỗi di chuyển 3 nhanh nhất của tôi. Không thể tin được mọi người lại bỏ phiếu cho nó. Modulo là một khái niệm quan trọng và được nghĩ đến trong mọi cuốn sách mã số học. Làm cho nó dài dòng không có ý nghĩa gì vì Số học trong mã phải được viết càng gọn càng tốt. Khi khả năng nhận thức của chúng ta để hiểu số học tăng lên khi bạn có thể nhìn thấy bức tranh hoàn chỉnh là phản đối việc hiểu ý nghĩa của các biến riêng lẻ. IMO Đặt tên biến toàn diện là quan trọng trong logic nghiệp vụ nhưng không phải là số học, hoàn toàn ngược lại.
eonist

2
@GitSync Modulo là một khái niệm quan trọng nhưng nó chỉ tồn tại đối với số nguyên. Bạn nên hiểu sự khác biệt.
Sulthan

5
@GitSync Hoạt động modulo chỉ tồn tại đối với số nguyên. Bạn đang nói về phần còn lại. Giá trị thập phân có hai loại phần dư. Đó là lý do tại sao Swift quyết định thực hiện hoạt động rõ ràng. Việc tính toán phần dư số nguyên ( phần dư cắt ngắn ) trên các giá trị kép không phổ biến lắm .
Sulthan

1
@GitSync Có remainder(dividingBy:)truncatingRemainder(dividingBy:). Bạn có thể muốn đọc tài liệu cho cả hai. Ngoài ra, hãy tham khảo những câu hỏi tương tự cho C ++ stackoverflow.com/questions/6102948/...
Sulthan

2

Tôi thấy rằng những thứ sau hoạt động trong Swift 3:

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

nơi totalSecondsTimeInterval( Double).


3
Trộn giữa tầng và vòng không phải là một ý tưởng hay, ví dụ: đối với totalSeconds = 59.8mã của bạn tính 0 phút và 0 giây.
Martin R

Vâng bạn đã đúng. Trong thực tế, roundkhông cần thiết chút nào.
benwiggy

1

Không cần tạo toán tử mô-đun riêng cho các số dấu phẩy động, trừ khi bạn nghĩ rằng nó làm cho mã an toàn hơn. Bạn có thể nạp chồng %toán tử để chấp nhận các số dấu phẩy động như sau:

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

Sử dụng

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

Bây giờ bạn có thể sử dụng %với bất kỳ hai số dấu phẩy động nào của cùng một tye.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.