当前位置: 首页 > 面试题库 >

Go如何对常数执行算术运算?

竺和洽
2023-03-14
问题内容

我一直在阅读有关Go中的常量的文章,并且试图了解它们如何在内存中存储和使用。您可以在Go中对非常大的常量执行运算,并且只要结果适合内存,就可以将结果强制为类型。例如,10如您所料,此代码显示:

const Huge = 1e1000
fmt.Println(Huge / 1e999)

这是如何工作的?在某个时候,Go必须存储1e1000并存储1e999在内存中,以便对其执行操作。那么常量是如何存储的,Go如何对其进行算术运算呢?


问题答案:

简短摘要(TL; DR)在答案的结尾。

无类型的任意精度常量在运行时不存在,常量仅在编译时(在编译期间)存在。话虽如此,Go不必在运行时以任意精度表示常量,而仅在编译应用程序时。

为什么?因为常量不会被编译到可执行二进制文件中。他们不必是。让我们举个例子:

const Huge = 1e1000
fmt.Println(Huge / 1e999)

有一个不变Huge源代码
(并会在包对象),但它不会出现在你的可执行文件。相反,fmt.Println()将记录一个传递给它的值(类型为)来记录对函数的调用float64。因此在可执行文件中,只会记录一个float6410.01e1000可执行文件中没有任何数字的迹象。

float64类型派生自 无类型 常量的 默认
类型。是浮点文字。验证:
__Huge``1e1000

const Huge = 1e1000
x := Huge / 1e999
fmt.Printf("%T", x) // Prints float64

回到任意精度:

规格:常数:

数字常数表示任意精度的精确值,并且不会溢出。

因此,常数表示任意精度的精确值。如我们所见,无需在 运行时 以任意精度表示常量,但编译器仍必须在 编译时 执行某些 操作 。它 确实

显然,“无限”精度无法解决。但是没有必要,因为源代码本身不是“无限的”(源大小是有限的)。但是, 允许
真正任意精度仍然不切实际。因此,规范为此提供了一些自由给编译器:

实现限制:尽管数字常量在语言中具有任意精度,但是编译器可能会使用内部表示形式来实现它们,而精度有限。也就是说,每个实现都必须:

  • 用至少256位表示整数常量。
  • 表示浮点常数,包括复数常数的部分,尾数至少为256位,带符号的指数至少为32位。
  • 如果无法精确表示整数常数,则给出错误。
  • 如果由于溢出而无法表示浮点数或复数常量,则给出错误。
    * 如果由于精度限制而无法表示浮点数或复数常数,则四舍五入到最接近的可表示常数。这些要求既适用于文字常量,也适用于评估常量表达式的结果。

但是,还请注意,当上述所有内容都存在时,标准包为您提供了仍然可以以“任意”精度表示和使用值(常数)的方法,请参见package
go/constant。您可以查看其来源,以了解其实现方式。

实现在中go/constant/value.go。表示此类值的类型:

// A Value represents the value of a Go constant.
type Value interface {
    // Kind returns the value kind.
    Kind() Kind

    // String returns a short, human-readable form of the value.
    // For numeric values, the result may be an approximation;
    // for String values the result may be a shortened string.
    // Use ExactString for a string representing a value exactly.
    String() string

    // ExactString returns an exact, printable form of the value.
    ExactString() string

    // Prevent external implementations.
    implementsValue()
}

type (
    unknownVal struct{}
    boolVal    bool
    stringVal  string
    int64Val   int64                    // Int values representable as an int64
    intVal     struct{ val *big.Int }   // Int values not representable as an int64
    ratVal     struct{ val *big.Rat }   // Float values representable as a fraction
    floatVal   struct{ val *big.Float } // Float values not representable as a fraction
    complexVal struct{ re, im Value }
)

如您所见,该math/big包用于表示无类型的任意精度值。big.Int例如(来自math/big/int.go):

// An Int represents a signed multi-precision integer.
// The zero value for an Int represents the value 0.
type Int struct {
    neg bool // sign
    abs nat  // absolute value of the integer
}

nat(来自math/big/nat.go)在哪里:

// An unsigned integer x of the form
//
//   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
//
// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
// with the digits x[i] as the slice elements.
//
// A number is normalized if the slice contains no leading 0 digits.
// During arithmetic operations, denormalized values may occur but are
// always normalized before returning the final result. The normalized
// representation of 0 is the empty or nil slice (length = 0).
//
type nat []Word

最后Word是(来自math/big/arith.go

// A Word represents a single digit of a multi-precision unsigned integer.
type Word uintptr

摘要

在运行时: 预定义
类型提供有限的精度,但是您可以使用某些包(例如math/big和)“模拟”任意精度go/constant。在编译时:常量似乎提供了任意精度,但实际上,编译器可能无法做到这一点(不必这样做);但是规范仍然为所有编译器必须支持的常数提供了最低的精度,例如,整数常数必须至少以256位(32字节)表示(相比之下int64,“仅”
8字节)。

创建可执行二进制文件时,必须转换常量表达式的结果(具有任意精度),并用有限精度类型的值表示-这可能是不可能的,因此可能导致编译时错误。请注意,只有
结果( 而不是中间操作数)必须转换为有限精度,常数运算可以任意精度执行。

规范未定义如何实现这种任意精度或增强精度,math/big例如,将数字的“数字”存储在切片中(其中,数字不是以10为基数表示的数字,而“数字”
uintptr是类似于base的数字)。在4位元架构上显示4294967295,在64位元架构上甚至更大)。



 类似资料:
  • 问题内容: 我在csv文件中有一个日期列,说有这种格式的日期,我还有另外一列。在列中,我要填充紧接在日期列中提到的日期之后的日期。例如。如果date列具有日期,那么我想在Next_Day列中。 我们可以在excel中使用,但我不知道如何在Python中执行此操作。 请帮助我解决这个问题。 问题答案: 使用

  • 我有一个具有两个数据成员的泛型类。这是我写的一段代码 我想对num1和num2进行简单的算术运算,比如加法和减法,我还想进行简单的二进制运算,比如 但是这是不允许的,那么有人能告诉我如何执行这些任务吗?

  • 我必须为图像中的所有像素添加一些常量值 - 对于灰色图像和彩色图像。但我不知道我该怎么做。我通过BufferedImage阅读图像,并且我正在尝试获取2d像素数组。我发现了类似BufferedImage.getRGB()的东西,但它返回奇怪的值(负值和巨大值)。如何为我的缓冲图像添加一些价值?

  • 问题内容: 我试图更好地掌握numpy数组,所以我有一个关于它们的示例问题: 假设我有一个名为a的numpy数组。我想对进行操作,使其中的所有小于0的值递增,其余的保持不变。例如,如果我有: 我想返回: 最紧凑的语法是什么? 谢谢! 问题答案:

  • 我可以直接对原子变量执行算术运算吗? 因为我发现C标准库提供了很多实用函数,比如来执行原子变量和非原子变量之间的加法。但是,我很好奇,因为变量是原子的,我能直接对它进行算术运算吗?如以下代码所示:

  • 本文向大家介绍C#程序执行所有基本算术运算,包括了C#程序执行所有基本算术运算的使用技巧和注意事项,需要的朋友参考一下 C#中的基本算术运算符包括以下内容- 运算符 描述 + 加两个操作数 -- 从第一个减去第二个操作数 * 将两个操作数相乘 / 将分子除以除分子 % 模运算符和整数除后的余数 ++ 增量运算符将整数值增加一 - 减法运算符将整数值减一 要添加,请使用加法运算符- 同样,它适用于减