仓颉编程语言浮点数保留n位小数(四舍五入)问题及处理

浮点类型包括 Float16、 Float32 和 Float64,分别用于表示编码长度为 16-bit、 32-bit 和 64-bit 的浮点数(带小数部分的数字,如 3.14159、8.24 和 0.1 等)的类型。Float16、 Float32 和 Float64 分别对应 IEEE 754 中的半精度格式(即 binary16)、单精度格式(即 binary32)和双精度格式(即 binary64)。Float64 的精度约为小数点后 15 位,Float32 的精度约为小数点后 6 位,Float16 的精度约为小数点后 3 位。

示例

main() {
    println(3.1415926)  // 3.141593
    var a:Float64 = 3.1415926
    println(a)  // 3.141593
    var b:Float32 = 3.1415926
    println(b)  //3.141593
    var c:Float16 = 3.1415926
    println(c)  //3.140625,因为Float16 精度不足
}

运行效果:

convert

仓颉首个长期支持版本(LTS 1.0.0)标准库的convert包(std.convert),提供了类型转换和格式化功能。其中,格式化format函数可以提供给精度处理( 控制 小数点后面的位数)。

示例 使用parse函数常规转换

import std.convert.*

main() {

    let a:Float64 = 3.1415926
    println(a) // 输出: 3.141593   
    println("a= ${a.format(".10")}") // 输出:a= 3.1415926000

    let b:Float32 = 3.1415926
    println(b) // 输出:3.141593 
    println("b= ${b.format(".10")}") // 输出:b= 3.1415925026


    let c:Float16 = 3.1415926
    println(c) // 输出:3.140625  ?! 因为Float16 精度不足
    println("c= ${c.format(".10")}") // 输出:c= 3.1406250000
}

运行截图

也可以自定义的浮点数保留 n 位小数(四舍五入)函数,源码如下:

// 浮点数保留 n 位小数(四舍五入)
//在7 月推出首个长期支持版本(LTS 1.0.0)通过
// 第一个参数浮点数;第二个参数是小数位数
// 真正的实现只接受 Float64,
func formatFloat(v: Float64, digits: Int64): String {
    if (digits <= 0) {
        return Int64(v).toString()
    }

    // 1. 放大 10^n 倍
    var scale = 1
    for (_ in 0..digits) { scale *= 10 }

    // 2. 加 0.5 后截断,实现四舍五入
    let scaled = v * Float64(scale)
    let rounded = if (scaled >= 0.0) { scaled + 0.5 } else { scaled - 0.5 }
    let n = Int64(rounded)

    // 3. 拆整数 / 小数
    let intPart  = (n / scale).toString()
    var fracPart = (if (n < 0) { -n } else { n } % scale).toString()

    // 4. 左侧补零
    while (fracPart.size < digits) { fracPart = "0" + fracPart }

    return "${intPart}.${fracPart}"
}

// ---------- 测试 ----------
main() {
    println(formatFloat(192.0, 2))      // 192.00    
    println(formatFloat(123.4, 0))      // 123
    println(formatFloat(0.007, 3))      // 0.007
    println(formatFloat(-2.5556, 2))       // -2.50

    println(formatFloat(3.1415926, 3))  // 3.142
    var a:Float64 = 3.1415926
    println(formatFloat(a, 3))  // 3.142
    var b:Float32 = 3.1415926
    println(formatFloat(Float64(b), 3))  //3.142
    var c:Float16 = 3.1415926
    println(formatFloat(Float64(c), 3))  //3.141  这句为何是3.141而不是3.142,因为Float16 精度不足
}

运行输出:

1192.00
123  
0.007
-2.56
3.142
3.142
3.142
3.141

下面给出一个使用自定义formatFloat函数的例子

// 浮点数保留 n 位小数(四舍五入)
//在7 月推出首个长期支持版本(LTS 1.0.0)通过
// 第一个参数浮点数;第二个参数是小数位数
// 真正的实现只接受 Float64
private func formatFloat(v: Float64, digits: Int64): String {
    if (digits <= 0) {
        return Int64(v).toString()
    }

    // 1. 放大 10^n 倍
    var scale: Int64 = 1
    for (_ in 0..digits) { scale *= 10 }

    // 2. 加 0.5 后截断,实现四舍五入
    let scaled  = v * Float64(scale)
    let rounded = if (scaled >= 0.0) { scaled + 0.5 } else { scaled - 0.5 }
    let n       = Int64(rounded)

    // 3. 拆整数 / 小数
    let intPart  = (n / scale).toString()
    var fracPart = (if (n < 0) { -n } else { n } % scale).toString()

    // 4. 左侧补零
    while (fracPart.size < digits) { fracPart = "0" + fracPart }

    return "${intPart}.${fracPart}"
}

// 定义 struct 类型
struct Rectangle {
    public var width: Float32
    public var height: Float32

    public init(width: Float32, height: Float32) {
        this.width = width
        this.height = height
    }

    public func area() {
        width * height
    }
}

main() {
    // 创建 struct 实例
    var r = Rectangle(10.4, 20.6) // r.width = 10.4, r.height = 20.6
    let a = r.area()
    println("矩形面积是:${a}")  
    // let a1 = formatFloat(r.area(), 2)  // 思考这句为何不可以?
    let a1 = formatFloat(Float64(r.area()), 2) 
    println("矩形面积是:${a1}")   
}

运行输出:

矩形面积是:214.239990
矩形面积是:214.24

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐