当前位置: 首页>>编程示例 >>用法及示例精选 >>正文


Swift FloatingPoint用法及代码示例

协议

FloatingPoint

浮点数值类型。

声明

protocol FloatingPoint : Hashable, SignedNumeric, Strideable where Self == Self.Magnitude

概述

浮点类型用于表示小数,如 5.5、100.0 或 3.14159274。每种浮点类型都有自己可能的范围和精度。标准库中的浮点类型是 FloatDoubleFloat80 (如果可用)。

使用整数或浮点文字创建浮点类型的新实例。例如:


let temperature = 33.2
let recordHigh = 37.5

FloatingPoint 协议声明了常见的算术运算,因此您可以编写适用于任何浮点类型的函数和算法。下面的示例声明了一个函数,该函数在给定两个垂直边的情况下计算直角三角形的斜边长度。因为hypotenuse(_:_:) 函数使用受FloatingPoint 协议约束的泛型参数,所以可以使用任何浮点类型调用它。


func hypotenuse<T: FloatingPoint>(_ a: T, _ b: T) -> T {
    return (a * a + b * b).squareRoot()
}


let (dx, dy) = (3.0, 4.0)
let distance = hypotenuse(dx, dy)
// distance == 5.0

浮点值表示为 signmagnitude ,其中大小是使用类型的 radix 和实例的 significandexponent 计算的。对于 F 类型的浮点值 x,此幅度计算采用以下形式,其中 ** 是幂:


x.significand * F.radix ** x.exponent

这是一个数字 -8.5 的示例,表示为 Double 类型的实例,它定义了 2 的基数。


let y = -8.5
// y.sign == .minus
// y.significand == 1.0625
// y.exponent == 3


let magnitude = 1.0625 * Double(2 ** 3)
// magnitude == 8.5

符合 FloatingPoint 协议的类型提供了 IEEE 754 specification 的最基本(第 5 条)操作。该协议不以任何方式固定基数、精度和指数范围,但它强制执行任何 IEEE 754 浮点类型的基本要求。

其他注意事项

除了表示特定数字外,浮点类型还具有用于处理溢出和非数字计算结果的特殊值。

无穷

任何幅度如此之大以至于会舍入到可表示数字范围之外的值的任何值都将舍入为 infinity 。对于类型 F ,正无穷和负无穷分别表示为 F.infinity-F.infinity 。正无穷比较大于每个有限值和负无穷,而负无穷比较小于每个有限值和正无穷。具有相同符号的无限值彼此相等。


let values: [Double] = [10.0, 25.0, -10.0, .infinity, -.infinity]
print(values.sorted())
// Prints "[-inf, -10.0, 10.0, 25.0, inf]"

具有无限值的运算尽可能遵循实数运算:将有限值相加或相减,或将无穷大乘以或除以非零有限值,得到无穷大。

NaN (“not a number”)

浮点类型表示既不是有限数也不是无穷大的值,如 NaN,“not a number”的缩写。将 NaN 与任何值(包括另一个 NaN)进行比较会得到 false


let myNaN = Double.nan
print(myNaN > 0)
// Prints "false"
print(myNaN < 0)
// Prints "false"
print(myNaN == .nan)
// Prints "false"

因为测试一个 NaN 是否等于另一个 NaN 会导致 false ,所以使用 isNaN 属性来测试一个值是否为 NaN。


print(myNaN.isNaN)
// Prints "true"

NaN 通过许多算术运算传播。当您对多个值进行操作时,此行为很有值,因为对 NaN 的操作只是转发值并且不会导致运行时错误。以下示例显示NaN 值如何在不同的上下文中运行。

假设您有一组温度数据,您需要为其报告一些一般统计数据:观测总数、有效观测数和平均温度。首先,将一组摄氏温度的观察值从字符串解析为 Double 值:


let temperatureData = ["21.5", "19.25", "27", "no data", "28.25", "no data", "23"]
let tempsCelsius = temperatureData.map { Double($0) ?? .nan }
print(tempsCelsius)
// Prints "[21.5, 19.25, 27, nan, 28.25, nan, 23.0]"

请注意,temperatureData 数组中的某些元素不是有效数字。当 Double 可失败初始化程序解析这些无效字符串时,该示例使用 nil-coalescing 运算符 (??) 提供 NaN 作为后备值。

接下来,将摄氏温度转换为华氏温度:


let tempsFahrenheit = tempsCelsius.map { $0 * 1.8 + 32 }
print(tempsFahrenheit)
// Prints "[70.7, 66.65, 80.6, nan, 82.85, nan, 73.4]"

tempsCelsius 数组中的 NaN 值通过转换传播并在 tempsFahrenheit 中保持 NaN 。

因为计算观测值的平均值涉及组合 tempsFahrenheit 数组的每个值,所以任何 NaN 值都会导致结果也为 NaN,如下例所示:


let badAverage = tempsFahrenheit.reduce(0.0, +) / Double(tempsFahrenheit.count)
// badAverage.isNaN == true

相反,当您需要一个运算来获得特定的数值结果时,请使用 isNaN 属性过滤掉任何 NaN 值。


let validTemps = tempsFahrenheit.filter { !$0.isNaN }
let average = validTemps.reduce(0.0, +) / Double(validTemps.count)

最后,报告平均温度和观测计数:


print("Average: \(average)°F in \(validTemps.count) " +
      "out of \(tempsFahrenheit.count) observations.")
// Prints "Average: 74.84°F in 5 out of 7 observations."

可用版本

iOS 8.0+, iPadOS 8.0+, macOS 10.10+, Mac Catalyst 13.0+, tvOS 9.0+, watchOS 2.0+

相关用法


注:本文由纯净天空筛选整理自apple.com大神的英文原创作品 FloatingPoint。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。