วิธีการปัด Double ไปยัง Int ที่ใกล้ที่สุดอย่างรวดเร็ว


170

ฉันพยายามสร้างเครื่องคิดเลขของอัตราการเติบโต ( Double) ที่จะปัดเศษผลลัพธ์เป็นจำนวนเต็มที่ใกล้ที่สุดและคำนวณใหม่จากที่นั่นเช่น:

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
}

แต่ฉันไม่สามารถทำได้จนถึงตอนนี้

แก้ไข ฉันชอบมันมาก:

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
}

แม้ว่าฉันจะไม่คิดว่ามันจะถูกปัดเศษลงเสมอฉันไม่ชอบเพราะfirstUsersต้องเป็นตัวแปรและเปลี่ยนแปลงตลอดโปรแกรม (เพื่อทำการคำนวณครั้งต่อไป) ซึ่งฉันไม่ต้องการให้มันเกิดขึ้น

คำตอบ:


253

มีความเป็นroundอยู่ในFoundationห้องสมุด(มันจริงDarwinแต่Foundationการนำเข้าDarwinและส่วนใหญ่ของเวลาที่คุณจะต้องการใช้Foundationแทนการใช้Darwinโดยตรง)

import Foundation

users = round(users)

ใช้รหัสของคุณในสนามเด็กเล่นแล้วโทร:

print(round(users))

ขาออก:

15.0

round()จะปัดเศษขึ้นเสมอเมื่อตำแหน่งทศนิยมเป็น>= .5และลดลงเสมอ< .5(ปัดเศษแบบมาตรฐาน) คุณสามารถใช้floor()เพื่อบังคับให้ปัดเศษลงและceil()เพื่อบังคับให้ปัดเศษขึ้น

หากคุณจำเป็นต้องรอบไปยังสถานที่ที่เฉพาะเจาะจงแล้วคุณคูณด้วยpow(10.0, number of places), roundและจากนั้นหารด้วยpow(10, number of places):

ทศนิยมทศนิยม 2 ตำแหน่ง:

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

ขาออก:

10.12

หมายเหตุ:เนื่องจากวิธีการทางคณิตศาสตร์ของเลขทศนิยมroundedอาจไม่แม่นยำอย่างสมบูรณ์ เป็นการดีที่สุดที่จะคิดถึงการปัดเศษมากกว่าการประมาณ หากคุณทำเช่นนี้เพื่อจุดประสงค์ในการแสดงผลควรใช้การจัดรูปแบบสตริงเพื่อจัดรูปแบบตัวเลขแทนที่จะใช้คณิตศาสตร์เพื่อปัดเศษ


อืมpow()น่าเสียดายที่ไม่สามารถใช้ได้ในสนามเด็กเล่น
MrBr

1
@MrBr pow()ถูกกำหนดไว้ในไลบรารีของดาร์วินดังนั้นคุณต้องimport Darwinก่อน (หรือimport Foundationหรือimport Cocoaหรือimport UIKitทั้งหมดซึ่งท้ายการนำเข้าดาร์วินภายใน)
Mike S

54
นอกจากนี้ยังมีที่ส่งกลับlround() Int
Martin R

1
" round()ปัดเศษขึ้นเสมอเมื่อตำแหน่งทศนิยมคือ> = .5 และลดลงเมื่อเป็น <.5 (การปัดเศษแบบมาตรฐาน)" ยกเว้นเมื่อไม่ได้ round(-16.5)ส่งกลับค่า -17 ไม่ใช่ -16 นี่เป็นข้อบกพร่องหรือไม่?
Daniel T.

1
@DanielT - ไม่ใช่ข้อบกพร่อง มันปัดเศษขึ้นเป็นจำนวนลบที่ใกล้เคียงที่สุด คิดแบบนี้ +16.5 ถึง +17 กำลังขยับ 0.5 ห่างจากศูนย์ นั่นหมายความว่า -16.5 ถึง -17 ก็อยู่ห่างจากศูนย์ 0.5 Ceil น่าจะตรงข้าม +16.5 ถึง +16 คือ 0.5 ใกล้กับศูนย์และ -16.5 ถึง -16 ก็คือ 0.5 ใกล้กับศูนย์
adougies

139

round()เข้าสู่รอบสองไปเลขที่ใกล้ที่สุดให้ใช้เพียง

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

หากคุณไม่ต้องการแก้ไขค่าดั้งเดิมให้ใช้rounded():

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

ในฐานะที่เป็นหนึ่งอาจคาดหวัง ( หรืออาจไม่ ) จำนวนเช่น3.5ถูกปัดเศษขึ้นและจำนวนเช่น-3.5ถูกปัดเศษลง หากคุณต้องการพฤติกรรมการปัดเศษที่แตกต่างกันไปกว่านั้นคุณสามารถใช้หนึ่งของกฎการปัดเศษ ตัวอย่างเช่น:

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

หากคุณต้องการของจริงIntให้โยนมันไปที่หนึ่ง (แต่ถ้าคุณมั่นใจว่า Double จะไม่มากกว่าInt.max):

let myInt = Int(myDouble.rounded())

หมายเหตุ

  • คำตอบนี้เขียนใหม่ทั้งหมด คำตอบเก่าของฉันจัดการกับ C ฟังก์ชั่นทางคณิตศาสตร์เช่นround, lround, และfloor ceilอย่างไรก็ตามตอนนี้ Swift มีฟังก์ชั่นนี้อยู่แล้วฉันไม่สามารถแนะนำให้ใช้ฟังก์ชั่นเหล่านี้ได้อีกต่อไป ขอบคุณ @dfri ที่ชี้ให้ฉันเห็น ตรวจสอบ@ คำตอบที่ดี dfri ที่นี่ ฉันยังทำอะไรบางอย่างที่คล้ายกันสำหรับปัดเศษCGFloat

Int (myDouble.rounded ()) <--- นี่อาจทำให้เกิดข้อยกเว้นได้ถ้าทั้งคู่ไม่เหมาะกับ Int
Toad

@ โหลดแน่นอนคุณแน่ใจ ฉันไม่เห็นว่าในเอกสาร
Suragch

ฉันเพิ่งแก้ไขข้อผิดพลาดในการผลิตด้วยปัญหาที่แน่นอนนี้ แต่แม้ว่าฉันจะผิดและมันจะไม่ผิดพลาดก็ยังคงให้ผลที่ไม่คาดคิดสำหรับคู่> maxint
คางคก

1
@ โหลดถูกต้องจุดดีขอบคุณ ฉันเพิ่มบันทึกย่อไปยังคำตอบ
Suragch

85

Swift 3 & 4 - ใช้ประโยชน์จากrounded(_:)วิธีพิมพ์เขียวในFloatingPointโปรโตคอล

FloatingPointโปรโตคอล (ซึ่งเช่นDoubleและFloatสอด) พิมพ์เขียวrounded(_:)วิธี

func rounded(_ rule: FloatingPointRoundingRule) -> Self

โดยFloatingPointRoundingRuleenum จะระบุกฎการปัดเศษที่แตกต่างกันจำนวนหนึ่งอยู่ที่ไหน:

case awayFromZero

ปัดเศษเป็นค่าที่อนุญาตที่ใกล้เคียงที่สุดซึ่งมีขนาดใหญ่กว่าหรือเท่ากับของแหล่งที่มา

case down

ปัดเศษเป็นค่าที่อนุญาตที่ใกล้เคียงที่สุดซึ่งน้อยกว่าหรือเท่ากับแหล่งที่มา

case toNearestOrAwayFromZero

ปัดเศษเป็นค่าที่อนุญาตใกล้เคียงที่สุด หากสองค่าใกล้กันเท่ากันค่าที่มีขนาดใหญ่กว่าจะถูกเลือก

case toNearestOrEven

ปัดเศษเป็นค่าที่อนุญาตใกล้เคียงที่สุด หากสองค่าใกล้กันเท่ากันค่าที่เลือกไว้

case towardZero

ปัดเศษเป็นค่าที่อนุญาตที่ใกล้เคียงที่สุดซึ่งมีขนาดน้อยกว่าหรือเท่ากับของแหล่งที่มา

case up

ปัดเศษเป็นค่าที่อนุญาตที่ใกล้เคียงที่สุดที่มากกว่าหรือเท่ากับแหล่งที่มา

เราใช้ตัวอย่างที่คล้ายกันกับคำตอบที่ยอดเยี่ยมของ @ Suragchเพื่อแสดงตัวเลือกการปัดเศษที่แตกต่างกันเหล่านี้ในทางปฏิบัติ

.awayFromZero

ปัดเศษเป็นค่าที่อนุญาตที่ใกล้เคียงที่สุดซึ่งมีขนาดใหญ่กว่าหรือเท่ากับของแหล่งที่มา ไม่มีตรงเทียบเท่าหมู่ฟังก์ชัน C ในขณะที่การใช้งานนี้มีเงื่อนไขในการเข้าสู่ระบบของself, ceilหรือfloorสำหรับในเชิงบวกและเชิงลบของค่าselfตามลำดับ

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

เทียบเท่ากับfloorฟังก์ชั่น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

เทียบเท่ากับroundฟังก์ชั่น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

กฎการปัดเศษนี้ยังสามารถเข้าถึงได้โดยใช้ศูนย์การโต้แย้งวิธีrounded()

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

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

.toNearestOrEven

ปัดเศษเป็นค่าที่อนุญาตที่ใกล้เคียงที่สุด; หากสองค่าใกล้กันเท่ากันค่าที่เลือกนั้น เทียบเท่ากับฟังก์ชั่นC rint(/ คล้ายกันมาก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

เทียบเท่ากับtruncฟังก์ชั่น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

หากวัตถุประสงค์ของการปัดเศษคือการเตรียมการทำงานกับจำนวนเต็ม (เช่นการใช้IntโดยการFloatPointเตรียมใช้งานหลังจากการปัดเศษ) เราอาจใช้ข้อเท็จจริงที่ว่าเมื่อเริ่มต้นการIntใช้Double(หรือFloatฯลฯ ) ส่วนทศนิยมจะถูกตัดออก

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

เทียบเท่ากับceilฟังก์ชั่น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

ภาคผนวก: การเยี่ยมชมซอร์สโค้ดสำหรับFloatingPointตรวจสอบฟังก์ชัน C ที่เทียบเท่ากับFloatingPointRoundingRuleกฎต่างๆ

หากเราต้องการเราสามารถดูซอร์สโค้ดของFloatingPointโปรโตคอลเพื่อดูฟังก์ชัน C โดยตรงกับFloatingPointRoundingRuleกฎสาธารณะ

จากswift / stdlib / public / core / FloatingPoint.swift.gybเราเห็นว่าการใช้งานเริ่มต้นของrounded(_:)วิธีทำให้เรากลายเป็นround(_:)วิธีการกลายพันธุ์:

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

จากswift / stdlib / public / core / FloatingPointTypes.swift.gybเราพบว่ามีการใช้งานเริ่มต้นround(_:)ซึ่งมีความเท่าเทียมกันระหว่างFloatingPointRoundingRuleกฎและฟังก์ชั่นการปัดเศษ C:

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 ขอบคุณสำหรับข้อความแจ้งฉันได้อัปเดตชื่อคำตอบแล้ว
dfri

ถ้าฉันต้องการสมการใด ๆ เช่น, 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: หากคุณต้องการปัดเศษให้เป็นตัวเลขที่แน่นอนเช่น 5.678434 -> 5.68 คุณสามารถรวมฟังก์ชัน round () หรือ roundf () เข้ากับการคูณ:

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

4

คุณยังสามารถขยาย FloatingPoint ใน Swift 3 ดังต่อไปนี้:

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

    }
}

324.0.rounded(to: 5)   // 325

คุณช่วยอธิบายสิ่งนี้ได้ไหม อะไรSelfหมายถึง?
JZAU

@Jacky Self หมายถึงคลาส FloatingPoint ในขณะที่ตนเองอ้างถึงอินสแตนซ์ของคลาสนั้น
George Yacoub

@ GeorgeYacoub Self หมายถึงประเภทที่สอดคล้องกับ FloatingPoint ที่ถูกขยาย (ในการใช้งานตัวอย่างนั้นเป็น Double) แต่พวกมันเป็นโครงสร้างไม่ใช่คลาส
Leo Dabus

2

สวิฟท์ 3

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

ดี ก่อนหน้านี้ฉันไม่รู้เรื่องนี้มาก่อน One note: myNum.rounded()ไม่เปลี่ยนแปลงmyNumแต่myNum.round()จะเปลี่ยน
Suragch

@Suragch ฉันได้แก้ไขคำตอบเพื่อสะท้อนความคิดเห็นของคุณ
Adil Hussain

0

คุณอาจต้องการตรวจสอบว่า double นั้นสูงกว่าค่า max สูงสุดก่อนที่จะลองแปลงค่าเป็น Int

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

-1

ทางออกที่ง่ายมากสำหรับฉัน:

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

จำนวนมีค่า 2

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.