Làm thế nào để làm tròn một Double đến Int gần nhất trong swift?


170

Tôi đang cố gắng tạo một máy tính về tốc độ tăng trưởng ( Double) sẽ làm tròn kết quả đến Số nguyên gần nhất và tính toán lại từ đó, như sau:

let firstUsers = 10.0
let growth = 0.1
var users = firstUsers
var week = 0


while users < 14 {
    println("week \(week) has \(users) users")
    users += users * growth
    week += 1
}

nhưng tôi đã không thể cho đến nay.

EDIT Tôi đã làm như vậy:

var firstUsers = 10.0
let growth = 0.1
var users:Int = Int(firstUsers)
var week = 0


while users <= 14 {
    println("week \(week) has \(users) users")
    firstUsers += firstUsers * growth
    users = Int(firstUsers)
    week += 1
}

Mặc dù tôi không bận tâm rằng nó luôn luôn làm tròn, tôi không thích nó vì firstUsersphải trở thành một biến số và thay đổi trong suốt chương trình (để thực hiện phép tính tiếp theo), điều mà tôi không muốn nó xảy ra.

Câu trả lời:


253

roundsẵn trong Foundationthư viện (thực tế là trong đó Darwin, nhưng Foundationnhập khẩu Darwinvà hầu hết thời gian bạn sẽ muốn sử dụng Foundationthay vì sử dụng Darwintrực tiếp) .

import Foundation

users = round(users)

Chạy mã của bạn trong một sân chơi và sau đó gọi:

print(round(users))

Đầu ra:

15.0

round()luôn làm tròn lên khi vị trí thập phân là >= .5và xuống khi nó < .5(làm tròn tiêu chuẩn). Bạn có thể sử dụng floor()để buộc làm tròn xuống, và ceil()để làm tròn lên.

Nếu bạn cần phải tròn đến một nơi cụ thể, sau đó bạn nhân với pow(10.0, number of places), roundvà sau đó chia cho pow(10, number of places):

Làm tròn đến 2 chữ số thập phân:

let numberOfPlaces = 2.0
let multiplier = pow(10.0, numberOfPlaces)
let num = 10.12345
let rounded = round(num * multiplier) / multiplier
print(rounded)

Đầu ra:

10,12

Lưu ý: Do cách hoạt động của toán học dấu phẩy động, roundedcó thể không phải lúc nào cũng chính xác hoàn toàn. Tốt nhất nên nghĩ về nó nhiều hơn về một phép làm tròn. Nếu bạn đang làm điều này cho mục đích hiển thị, tốt hơn là sử dụng định dạng chuỗi để định dạng số thay vì sử dụng toán học để làm tròn số.


Rất pow()tiếc, không có sẵn trong một sân chơi
MrBr

1
@MrBr, pow()được định nghĩa trong thư viện Darwin, vì vậy import Darwintrước tiên bạn cần ( import Foundationhoặc import Cocoahoặc import UIKit, tất cả trong số đó kết thúc nhập Darwin nội bộ).
Mike S

54
Cũng lround()có trả về một Int.
Martin R

1
" round()luôn làm tròn lên khi vị trí thập phân> = .5 và giảm xuống khi nó <.5 (làm tròn tiêu chuẩn)." Ngoại trừ khi nó không. round(-16.5)trả về -17, không phải -16. Đây có phải là một lỗi?
Daniel T.

1
@DanielT. - không phải là một lỗi. Đó là làm tròn đến số âm lớn hơn gần nhất. Hãy suy nghĩ về nó theo cách này, +16,5 đến +17 đang di chuyển 0,5 từ 0. Điều đó có nghĩa là -16,5 đến -17 cũng cách xa 0,5. Ceil sẽ ngược lại, +16,5 đến +16 gần 0,5 hơn 0 và -16,5 đến -16 cũng gần 0,5 hơn 0
adougies 21/10/19

139

Để làm tròn một số đến số nguyên gần nhất, chỉ cần sử dụng round().

var x = 3.7
x.round() // x = 4.0

Nếu bạn không muốn sửa đổi giá trị ban đầu, thì hãy sử dụng rounded():

let x = 3.7
let y = x.rounded() // y = 4.0. x = 3.7

Như người ta có thể mong đợi ( hoặc có thể không ), một số like 3.5được làm tròn lên và một số like -3.5được làm tròn xuống. Nếu bạn cần hành vi làm tròn khác nhau, bạn có thể sử dụng một trong các quy tắc làm tròn . Ví dụ:

var x = 3.7
x.round(.towardZero) // 3.0

Nếu bạn cần một thực tế Intthì chỉ cần đặt nó thành một (nhưng chỉ khi bạn chắc chắn rằng Double sẽ không lớn hơn Int.max):

let myInt = Int(myDouble.rounded())

Ghi chú

  • Câu trả lời này được viết lại hoàn toàn. Câu trả lời cũ của tôi xử lý với C hàm toán học thích round, lround, floor, và ceil. Tuy nhiên, bây giờ Swift đã tích hợp chức năng này, tôi không còn có thể khuyên bạn nên sử dụng các chức năng đó nữa. Cảm ơn @dfri đã chỉ ra điều này cho tôi. Kiểm tra câu trả lời tuyệt vời của @ dfri ở đây . Tôi cũng đã làm một cái gì đó tương tự để làm tròn aCGFloat .

Int (myDouble.rounded ()) <--- điều này thực sự có thể tạo ra một ngoại lệ nếu cú ​​đúp không phù hợp với Int
Toad

@Toad, bạn có chắc không? Tôi không thấy điều đó trong tài liệu .
Suragch

Tôi chỉ giải quyết một sự cố trong sản xuất với vấn đề chính xác này. Nhưng ngay cả khi tôi sai và nó sẽ không sụp đổ, thì nó vẫn sẽ mang lại kết quả bất ngờ cho nhân đôi> maxint
cóc

1
@Toad, đúng, điểm tốt, cảm ơn. Tôi đã thêm một ghi chú cho câu trả lời.
Suragch

85

Swift 3 & 4 - sử dụng rounded(_:)phương thức như được thiết kế trong FloatingPointgiao thức

Các FloatingPointgiao thức (mà ví dụ DoubleFloatchiếu theo) đồ án các rounded(_:)phương pháp

func rounded(_ rule: FloatingPointRoundingRule) -> Self

Trường hợp FloatingPointRoundingRuleliệt kê một số quy tắc làm tròn khác nhau:

case awayFromZero

Làm tròn đến giá trị được phép gần nhất có cường độ lớn hơn hoặc bằng giá trị của nguồn.

case down

Làm tròn đến giá trị được phép gần nhất nhỏ hơn hoặc bằng nguồn.

case toNearestOrAwayFromZero

Làm tròn đến giá trị cho phép gần nhất; nếu hai giá trị gần bằng nhau, thì giá trị lớn hơn sẽ được chọn.

case toNearestOrEven

Làm tròn đến giá trị cho phép gần nhất; nếu hai giá trị gần bằng nhau, thì một giá trị chẵn được chọn.

case towardZero

Làm tròn đến giá trị được phép gần nhất có cường độ nhỏ hơn hoặc bằng giá trị của nguồn.

case up

Làm tròn đến giá trị được phép gần nhất lớn hơn hoặc bằng nguồn.

Chúng tôi sử dụng các ví dụ tương tự với các ví dụ từ câu trả lời xuất sắc của @ Suragch để hiển thị các tùy chọn làm tròn khác nhau này trong thực tế.

.awayFromZero

Làm tròn đến giá trị cho phép gần nhất có cường độ lớn hơn hoặc bằng giá trị của nguồn; không tương đương trực tiếp giữa các hàm C, vì điều này sử dụng, theo điều kiện có dấu self, ceilhoặc floor, cho các giá trị dương và âm selftương ứng.

3.000.rounded(.awayFromZero) // 3.0
3.001.rounded(.awayFromZero) // 4.0
3.999.rounded(.awayFromZero) // 4.0

(-3.000).rounded(.awayFromZero) // -3.0
(-3.001).rounded(.awayFromZero) // -4.0
(-3.999).rounded(.awayFromZero) // -4.0

.down

Tương đương với floorhàm C.

3.000.rounded(.down) // 3.0
3.001.rounded(.down) // 3.0
3.999.rounded(.down) // 3.0

(-3.000).rounded(.down) // -3.0
(-3.001).rounded(.down) // -4.0
(-3.999).rounded(.down) // -4.0

.toNearestOrAwayFromZero

Tương đương với roundhàm C.

3.000.rounded(.toNearestOrAwayFromZero) // 3.0
3.001.rounded(.toNearestOrAwayFromZero) // 3.0
3.499.rounded(.toNearestOrAwayFromZero) // 3.0
3.500.rounded(.toNearestOrAwayFromZero) // 4.0
3.999.rounded(.toNearestOrAwayFromZero) // 4.0

(-3.000).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.001).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.499).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.500).rounded(.toNearestOrAwayFromZero) // -4.0
(-3.999).rounded(.toNearestOrAwayFromZero) // -4.0

Quy tắc làm tròn này cũng có thể được truy cập bằng rounded()phương thức đối số bằng không .

3.000.rounded() // 3.0
// ...

(-3.000).rounded() // -3.0
// ...

.toNearestOrEven

Làm tròn đến giá trị cho phép gần nhất; nếu hai giá trị gần bằng nhau, một giá trị chẵn được chọn; tương đương với hàm C rint(/ rất giống với nearbyint).

3.499.rounded(.toNearestOrEven) // 3.0
3.500.rounded(.toNearestOrEven) // 4.0 (up to even)
3.501.rounded(.toNearestOrEven) // 4.0

4.499.rounded(.toNearestOrEven) // 4.0
4.500.rounded(.toNearestOrEven) // 4.0 (down to even)
4.501.rounded(.toNearestOrEven) // 5.0 (up to nearest)

.towardZero

Tương đương với trunchàm C.

3.000.rounded(.towardZero) // 3.0
3.001.rounded(.towardZero) // 3.0
3.999.rounded(.towardZero) // 3.0

(-3.000).rounded(.towardZero) // 3.0
(-3.001).rounded(.towardZero) // 3.0
(-3.999).rounded(.towardZero) // 3.0

Nếu mục đích của làm tròn là để chuẩn bị làm việc với một số nguyên (ví dụ: sử dụng bằng Intcách FloatPointkhởi tạo sau khi làm tròn), chúng ta có thể chỉ cần sử dụng thực tế là khi khởi tạo Intbằng cách sử dụng một Double(hoặc Floatvv), phần thập phân sẽ bị cắt bớt.

Int(3.000) // 3
Int(3.001) // 3
Int(3.999) // 3

Int(-3.000) // -3
Int(-3.001) // -3
Int(-3.999) // -3

.up

Tương đương với ceilhàm C.

3.000.rounded(.up) // 3.0
3.001.rounded(.up) // 4.0
3.999.rounded(.up) // 4.0

(-3.000).rounded(.up) // 3.0
(-3.001).rounded(.up) // 3.0
(-3.999).rounded(.up) // 3.0

Phụ lục: truy cập mã nguồn FloatingPointđể xác minh các hàm C tương đương với các FloatingPointRoundingRulequy tắc khác nhau

Nếu muốn, chúng ta có thể xem mã nguồn của FloatingPointgiao thức để xem trực tiếp các hàm C tương đương với các FloatingPointRoundingRulequy tắc chung.

Từ swift / stdlib / public / core / FloatingPoint.swift.gyb, chúng ta thấy rằng việc triển khai mặc định của rounded(_:)phương thức làm cho chúng ta có round(_:)phương thức biến đổi :

public func rounded(_ rule: FloatingPointRoundingRule) -> Self {
    var lhs = self
    lhs.round(rule)
    return lhs
}

Từ swift / stdlib / public / core / FloatingPointTypes.swift.gyb, chúng tôi thấy việc triển khai mặc định round(_:), trong đó sự tương đương giữa các FloatingPointRoundingRulequy tắc và các hàm làm tròn C là rõ ràng:

public mutating func round(_ rule: FloatingPointRoundingRule) {
    switch rule {
    case .toNearestOrAwayFromZero:
        _value = Builtin.int_round_FPIEEE${bits}(_value)
    case .toNearestOrEven:
        _value = Builtin.int_rint_FPIEEE${bits}(_value)
    case .towardZero:
        _value = Builtin.int_trunc_FPIEEE${bits}(_value)
    case .awayFromZero:
        if sign == .minus {
            _value = Builtin.int_floor_FPIEEE${bits}(_value)
        }
        else {
            _value = Builtin.int_ceil_FPIEEE${bits}(_value)
        }
    case .up:
        _value = Builtin.int_ceil_FPIEEE${bits}(_value)
    case .down:
        _value = Builtin.int_floor_FPIEEE${bits}(_value)
    }
}

@iosMentalist cảm ơn vì lời nhắc, tôi đã cập nhật tiêu đề câu trả lời.
dfri

Nếu tôi muốn bất kỳ phương trình nào như, 3.0 = 3, 3.1 = 3.5, 3.4 = 3.5, 3.6 = 4, 3.9 - 4
PJR

6
**In Swift**

var a = 14.123456789
var b = 14.123456789
var c = 14.123456789
var d = 14.123456789
var e = 14.123456789
var f = 14.123456789

a.rounded(.up)                      //15
b.rounded(.down)                    //14
c.rounded(.awayFromZero)            //15
d.rounded(.towardZero)              //14
e.rounded(.toNearestOrAwayFromZero) //14
f.rounded(.toNearestOrEven)         //14

6

Swift 3: Nếu bạn muốn làm tròn đến một số chữ số nhất định, ví dụ 5.678434 -> 5.68, bạn chỉ cần kết hợp hàm round () hoặc roundf () với phép nhân:

let value:Float = 5.678434
let roundedValue = roundf(value * 100) / 100
print(roundedValue) //5.68

4

Bạn cũng có thể mở rộng FloatingPoint trong Swift 3 như sau:

extension FloatingPoint {
    func rounded(to n: Int) -> Self {
        let n = Self(n)
        return (self / n).rounded() * n

    }
}

324.0.rounded(to: 5)   // 325

Bạn có thể vui lòng giải thích điều này? Có Selfnghĩa là gì?
JZAU

@Jacky Tự đề cập đến lớp FloatingPoint trong khi bản thân đề cập đến thể hiện của lớp đó.
George Yacoub

@GeorgeYacoub Tự đề cập đến loại phù hợp với FloatingPoint đang được mở rộng (trong đó sử dụng mẫu là Double) nhưng chúng là các cấu trúc, không phải là các lớp
Leo Dabus

2

Swift 3

var myNum = 8.09
myNum.rounded() // result = 8 and leaves myNum unmodified

Đẹp. Tôi đã không biết về điều này trước đây. Một lưu ý: myNum.rounded()không thay đổi myNum, nhưng myNum.round()không.
Suragch

@Suragch, tôi đã chỉnh sửa câu trả lời để phản ánh nhận xét của bạn.
Adil Hussain

0

Bạn cũng có thể muốn kiểm tra xem giá trị nhân đôi có cao hơn giá trị Int tối đa hay không trước khi thử chuyển đổi giá trị thành Int.

let number = Double.infinity
if number >= Double(integerLiteral: Int64.max) {
  let rounded = Int.max
} else {
  let rounded = Int(number.rounded())
}

-1

Một giải pháp rất dễ dàng làm việc cho tôi:

  if (62 % 50 != 0) {
      var number = 62 / 50 + 1 // adding 1 is doing the actual "round up"
  }

số chứa giá trị 2

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.