当前位置: 首页 > 知识库问答 >
问题:

go中的浮点运算

闻人和泽
2023-03-14

以下是go中的示例代码:

package main

import "fmt"

func mult32(a, b float32) float32 { return a*b }
func mult64(a, b float64) float64 { return a*b }


func main() {
    fmt.Println(3*4.3)                  // A1, 12.9
    fmt.Println(mult32(3, 4.3))         // B1, 12.900001
    fmt.Println(mult64(3, 4.3))         // C1, 12.899999999999999

    fmt.Println(12.9 - 3*4.3)           // A2, 1.8033161362862765e-130
    fmt.Println(12.9 - mult32(3, 4.3))  // B2, -9.536743e-07
    fmt.Println(12.9 - mult64(3, 4.3))  // C2, 1.7763568394002505e-15

    fmt.Println(12.9 - 3*4.3)                               // A4, 1.8033161362862765e-130
    fmt.Println(float32(12.9) - float32(3)*float32(4.3))    // B4, -9.536743e-07
    fmt.Println(float64(12.9) - float64(3)*float64(4.3))    // C4, 1.7763568394002505e-15

}

结果线A1、B1和C1之间的差异是可以理解的。然而,从A2开始到C2魔法来了。来自B2和C2的结果都与来自A2线的结果不匹配。对于x2行(x=A、B或C)也是如此——但是x2和x4的输出是相同的。

为了确保,让我们以二进制形式打印结果。

    fmt.Printf("%b\n", 3*4.3)                   // A11, 7262054399134925p-49
    fmt.Printf("%b\n", mult32(3, 4.3))          // B11, 13526631p-20
    fmt.Printf("%b\n", mult64(3, 4.3))          // C11, 7262054399134924p-49

    fmt.Printf("%b\n", 12.9 - 3*4.3)            // A12, 4503599627370496p-483
    fmt.Printf("%b\n", 12.9 - mult32(3, 4.3))   // B12, -8388608p-43
    fmt.Printf("%b\n", 12.9 - mult64(3, 4.3))   // C12, 4503599627370496p-101

    fmt.Printf("%b\n", 12.9 - 3*4.3)                                // A14, 4503599627370496p-483
    fmt.Printf("%b\n", float32(12.9) - float32(3)*float32(4.3))     // B14, -8388608p-43
    fmt.Printf("%b\n", float64(12.9) - float64(3)*float64(4.3))     // C14, 4503599627370496p-101

上面代码中的一些事实(一个在bin表单中):

  1. 行A11和C11之间有差异(最后一位数字——就在指数之前)。
  2. 行A12和C12几乎相同(除了指数!!!),行A14和C14之间可以观察到相同。

问题来了:

  1. 如何计算裸(裸:))数?(每个Axx行的计算)
  2. 它们是由编译器执行的吗?
  3. 如果是,那么它们为什么不同?优化?
  4. 它们是在不同于IEE-754的系统中计算的吗?
  5. 如果是,为什么?
  6. 实现更精确的精度是否证明这种方法是合理的?

代码已经在64位linux上的“go run”和“go build”(go1.0.3)下进行了测试,也在该站点上进行了测试:http://tour.golang.org/

共有2个答案

裴欣然
2023-03-14

表示浮点常量,包括复数常量的部分,尾数至少为256位,有符号指数至少为32位。

请注意,Go 1.8(目前处于2016年第四季度的html" target="_blank">测试阶段,2017年第一季度发布)改变了这一定义:

语言规范现在只要求实现在浮点常量中最多支持16位指数。
这不影响"gc"或gccgo编译器,这两个编译器仍然支持32位指数。

那来自变化17711

16位二进制指数允许一个恒定的范围,大致覆盖从7e-9865到7e9863的范围,这对于任何实际和假设的恒定算术来说都是足够的。

此外,直到最近,cmd/compile仍然无法正确处理非常大的指数;i、 例如,任何真正的程序(但对于探索角落案例的测试)受到影响的可能性几乎为零。

最后,限制支持的最小范围可显著降低该领域的实现复杂性,对于不依赖或不能依赖支持32位指数范围的现有仲裁精度算术包的新的或替代的符合规范的实现来说,这在现实中几乎不重要。

从技术上讲,这是一种语言上的改变,但由于上述原因,这不太可能影响任何真正的程序,当然也不会影响用gc或gccgo编译器编译的程序,因为它们目前支持高达32位指数。

见第13572期,其中提到:

在Go 1.4中,编译器在没有用户投诉的情况下拒绝了大于10000的指数(因为知道代码不适用于较大的指数)。

在早期版本的Go中,大指数被默默地错误处理,用户也没有任何抱怨。

姚骁
2023-03-14

>

  • 常数:

    • 数值常量表示任意精度的值,不会溢出

    是的,由编译器编译时间常量。

    是的,它们是不同的:更精确。见1.

    是的,见1。

    最小化多项浮点常数表达式浮点误差的累积。

    当然可以。达到较低的精度是否曾经是一个目标?运行时浮点运算本质上是不完美的,这就足够了,不需要从常量表达式中增加更多的不精确性。

  •  类似资料:
    • 问题内容: 我对在Go中精确减去2个float的方法感兴趣。 我尝试使用该 库,但无法获得准确的结果。 我使用Javascript中的big.js库解决了此问题。Go算法是否有类似的库/方法? https://play.golang.org/p/vomAr87Xln 问题答案: 包装大 导入“数学/大” func(* Float)字符串 字符串格式x类似于x.Text(’g’,10)。(必须显式调

    • 对于这些代码行,我得到0作为输出,即它们都是相等的。现在,如果我理解正确,a b和c可能会存储稍微不同版本的真值.3因此,当做一个Float.compare(...)对这些值,我希望得到一个输出值,而不是0。为什么我把它们取为0?

    • 我阅读关于浮点和舍入在浮点算术期间发生的错误。 我读了很多关于IEEE754单精度/双精度格式的文章。我知道有符号位、8(或)11位指数和23(或)52位有效位以及隐式前导位。 我也知道分母不是质因数2的实数不能完全表示,例如二进制中的0.1是0.0001100110011...... 我知道0.1 0.1 0.1不等于0.3,因为舍入误差的累积。 同样,0.5也可以用二进制格式表示,因为它是1/

    • 前面两个小节我们我们都是在讲解整型的数据类型,也就是说都是整数,但是在开发中我们也会经常使用小数数据,这节课我们就主要介绍 Go 语言中处理小数的数据类型 1. 实数类型 Go 语言提供了两种精度的浮点数 float32 和 float64,它们的算术规范由 IEEE754 浮点数国际标准定义,该浮点数规范被所有现代的 CPU 支持。 序号 类型 长度 1 float32 1.4012984643

    • 本文向大家介绍DSP中浮点转定点运算--浮点与定点概述,包括了DSP中浮点转定点运算--浮点与定点概述的使用技巧和注意事项,需要的朋友参考一下 一:浮点与定点概述  1.1相关定义说明   定点数:通俗的说,小数点固定的数。以人民币为例,我们日常经常说到的如123.45¥,789.34¥等等,默认的情况下,小数点后面有两位小数,即角,分。如果小数点在最高有效位的前面,则这样的数称为纯小数的定点数,

    • 本文向大家介绍DSP中浮点转定点运算--浮点数的存储格式,包括了DSP中浮点转定点运算--浮点数的存储格式的使用技巧和注意事项,需要的朋友参考一下 二:浮点数的存储格式 2.1 IEEE floating point standard   上面我们说了,浮点数的小数点是不固定的,如果每个人都按照自己的爱好存储在电脑里,那不就乱套了吗?那么怎么在计算机中存储这种类型的数字呢?象这类古老的问题前人早都