在Swift中将float显示为可变数量的小数位

时间:2022-12-28 17:07:44

Is there a simple way of displaying a float or double to a relevant number of decimal places in Swift.

是否有一种简单的方法可以在Swift中显示一个float或double到相关的小数位数。

For example, an iOS app using SI units, which can be altered depending on the property desired, and converted through up to 6 orders of magnitude depending on desired inputs and output. Therefore it needs to display not only 1mg to 1000 micrograms, but also the other way around - i.e 1 microgram = 0.001 mg.

例如,使用SI单位的iOS应用程序,可根据所需属性进行更改,并根据所需的输入和输出进行最多6个数量级的转换。因此,它不仅需要显示1mg至1000微克,而且还需要显示相反的方式 - 即1微克= 0.001毫克。

I can easily format a string as follows:

我可以轻松地格式化字符串,如下所示:

textFieldFoo.text = NSString(format: "%.1f mg", bar) as String

However, if the user were to convert from 1mcg to 0.001mg, this would display as 0.0 mg

但是,如果用户将1mcg转换为0.001mg,则显示为0.0 mg

Yet, to include up to 6 decimal places to encompass all common possibilities would lead to an unwieldy, ugly looking UI.

然而,要包含最多6个小数位以包含所有常见的可能性将导致难看的丑陋UI。

Is there a simple way to format a string, in order to include a float/ double where it is displayed to a relevant number of decimal places/ significant figures? I'm sure, given time and enough boilerplate code, that I could pyramid if/ else it to get a result, but that's frankly inelegant.

是否有一种简单的方法来格式化字符串,以便包含一个float / double,它显示到相关的小数位数/有效数字?我敢肯定,鉴于时间和足够的样板代码,我可以金字塔,如果/它得到一个结果,但这是坦率地不优雅。

2 个解决方案

#1


1  

There's NSMAssFormatter but it doesn't go all the way down to microgram. It was designed to format human-level weight.

有NSMAssFormatter,但它不会一直到微克。它旨在形成人类体重的格式。

You can roll your own by subclassing NSNumberFormatter:

你可以通过继承NSNumberFormatter来自己动手:

enum MassUnit: Double {
    case Microgram = 1e-6
    case Milligram = 1e-3
    case Gram = 1
    case Kilogram = 1e3

    static let allUnits: [MassUnit] = [.Microgram, .Milligram, .Gram, .Kilogram]

    var unitAbbreviation: String {
        get {
            switch self {
            case .Microgram: return "mcg"
            case .Milligram: return "mg"
            case .Gram: return "g"
            case .Kilogram: return "kg"
            }

        }
    }
}

class MyMassFormatter: NSNumberFormatter {
    func bestFitStringForWeightInGrams(weight: Double) -> String {
        var selectedString = self.stringFromNumber(weight)!
        var selectedUnit = MassUnit.Gram

        // Pick the unit that results in the shortest string
        for unit in MassUnit.allUnits {
            if let str = self.stringFromNumber(weight / unit.rawValue)
                where str.characters.count < selectedString.characters.count {
                    selectedString = str
                    selectedUnit = unit
            }
        }

        return selectedString + selectedUnit.unitAbbreviation
    }
}

Usage:

let formatter = MyMassFormatter()
formatter.format = "0.######"

print(formatter.bestFitStringForWeightInGrams(0.000001))   // 1mcg
print(formatter.bestFitStringForWeightInGrams(0.005))      // 5mg
print(formatter.bestFitStringForWeightInGrams(2500))       // 2.5kg
print(formatter.bestFitStringForWeightInGrams(1234.5))     // 1234.5g

#2


0  

Formatting to Significant Figures using Swift

使用Swift格式化为重要数字

What you want is the ability to format to a fixed number of significant figures, rather than a fixed number of decimal places. A good swift option to solve this is using class extensions, with a little maths to decide how many decimal places to show based on the magnitude of the number.

你想要的是能够格式化为固定数量的有效数字,而不是固定的小数位数。解决这个问题的一个很好的快速选择是使用类扩展,用一些数学来决定根据数字的大小显示多少个小数位。

The example below extends the Double class to enable formatting to a fixed number of significant figures and uses either float notation or scientific notation depending on the magnitude of the number.

下面的示例扩展了Double类,以便将格式化为固定数量的有效数字,并使用浮点表示法或科学计数法,具体取决于数字的大小。

import Foundation

//extension to format a Double to a fixed number of significant figures
extension Double {
    func sigFigs(_ numberOfSignificantFigures: Int) -> String {

        let mag = log10(abs(self))
        let intMag = Int(mag)

        if mag >= 0 {
            if intMag < numberOfSignificantFigures {
                return String(format: "%.\(numberOfSignificantFigures - intMag - 1)f",self)
            }
            else {
                return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
            }
        }
        else {
            if -intMag < numberOfSignificantFigures {
                return String(format: "%.\(numberOfSignificantFigures)f",self)
            }
            else {
                return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
            }
        }
    }
}

Usage

let num1 = 1234.5678
let num2 = 12.345678
let num3 = 0.0012345678
let num4 = 1234567.8

print(num1.sigFigs(6))
print(num1.sigFigs(2))
print(num2.sigFigs(6))
print(num2.sigFigs(2))
print(num3.sigFigs(6))
print(num3.sigFigs(2))
print(num4.sigFigs(6))
print(num4.sigFigs(2))

Output

1234.57
1.2e+03
12.3457
12
0.001235
1.2e-03
1.23457e+06
1.2e+06

#1


1  

There's NSMAssFormatter but it doesn't go all the way down to microgram. It was designed to format human-level weight.

有NSMAssFormatter,但它不会一直到微克。它旨在形成人类体重的格式。

You can roll your own by subclassing NSNumberFormatter:

你可以通过继承NSNumberFormatter来自己动手:

enum MassUnit: Double {
    case Microgram = 1e-6
    case Milligram = 1e-3
    case Gram = 1
    case Kilogram = 1e3

    static let allUnits: [MassUnit] = [.Microgram, .Milligram, .Gram, .Kilogram]

    var unitAbbreviation: String {
        get {
            switch self {
            case .Microgram: return "mcg"
            case .Milligram: return "mg"
            case .Gram: return "g"
            case .Kilogram: return "kg"
            }

        }
    }
}

class MyMassFormatter: NSNumberFormatter {
    func bestFitStringForWeightInGrams(weight: Double) -> String {
        var selectedString = self.stringFromNumber(weight)!
        var selectedUnit = MassUnit.Gram

        // Pick the unit that results in the shortest string
        for unit in MassUnit.allUnits {
            if let str = self.stringFromNumber(weight / unit.rawValue)
                where str.characters.count < selectedString.characters.count {
                    selectedString = str
                    selectedUnit = unit
            }
        }

        return selectedString + selectedUnit.unitAbbreviation
    }
}

Usage:

let formatter = MyMassFormatter()
formatter.format = "0.######"

print(formatter.bestFitStringForWeightInGrams(0.000001))   // 1mcg
print(formatter.bestFitStringForWeightInGrams(0.005))      // 5mg
print(formatter.bestFitStringForWeightInGrams(2500))       // 2.5kg
print(formatter.bestFitStringForWeightInGrams(1234.5))     // 1234.5g

#2


0  

Formatting to Significant Figures using Swift

使用Swift格式化为重要数字

What you want is the ability to format to a fixed number of significant figures, rather than a fixed number of decimal places. A good swift option to solve this is using class extensions, with a little maths to decide how many decimal places to show based on the magnitude of the number.

你想要的是能够格式化为固定数量的有效数字,而不是固定的小数位数。解决这个问题的一个很好的快速选择是使用类扩展,用一些数学来决定根据数字的大小显示多少个小数位。

The example below extends the Double class to enable formatting to a fixed number of significant figures and uses either float notation or scientific notation depending on the magnitude of the number.

下面的示例扩展了Double类,以便将格式化为固定数量的有效数字,并使用浮点表示法或科学计数法,具体取决于数字的大小。

import Foundation

//extension to format a Double to a fixed number of significant figures
extension Double {
    func sigFigs(_ numberOfSignificantFigures: Int) -> String {

        let mag = log10(abs(self))
        let intMag = Int(mag)

        if mag >= 0 {
            if intMag < numberOfSignificantFigures {
                return String(format: "%.\(numberOfSignificantFigures - intMag - 1)f",self)
            }
            else {
                return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
            }
        }
        else {
            if -intMag < numberOfSignificantFigures {
                return String(format: "%.\(numberOfSignificantFigures)f",self)
            }
            else {
                return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
            }
        }
    }
}

Usage

let num1 = 1234.5678
let num2 = 12.345678
let num3 = 0.0012345678
let num4 = 1234567.8

print(num1.sigFigs(6))
print(num1.sigFigs(2))
print(num2.sigFigs(6))
print(num2.sigFigs(2))
print(num3.sigFigs(6))
print(num3.sigFigs(2))
print(num4.sigFigs(6))
print(num4.sigFigs(2))

Output

1234.57
1.2e+03
12.3457
12
0.001235
1.2e-03
1.23457e+06
1.2e+06