Floating point 对于单精度和双精度,是否有向量寄存器使用相同的指数位?

Floating point 对于单精度和双精度,是否有向量寄存器使用相同的指数位?,floating-point,precision,cpu-architecture,sse,simd,Floating Point,Precision,Cpu Architecture,Sse,Simd,可以将一对32位单精度浮点数存储在64位双精度数占用的相同空间中。例如,SSE2指令集的XMM寄存器可以存储四个单精度数字或两个双精度数字 根据IEEE 754标准,单精度和双精度之间的差异不仅在于精度本身,还在于可用范围:分别为8和11个指数位 直观地说,在我看来,如果设计一个FPU来并行处理2N个单精度数字或N个双精度数字,那么如果偏离IEEE标准并使两者使用相同数量的指数位,那么电路设计应该更简单。例如,bfloat16半精度格式,交换掉一些尾数位以保持与单精度相同的指数位数;部分理由是,

可以将一对32位单精度浮点数存储在64位双精度数占用的相同空间中。例如,SSE2指令集的XMM寄存器可以存储四个单精度数字或两个双精度数字

根据IEEE 754标准,单精度和双精度之间的差异不仅在于精度本身,还在于可用范围:分别为8和11个指数位

直观地说,在我看来,如果设计一个FPU来并行处理2N个单精度数字或N个双精度数字,那么如果偏离IEEE标准并使两者使用相同数量的指数位,那么电路设计应该更简单。例如,bfloat16半精度格式,交换掉一些尾数位以保持与单精度相同的指数位数;部分理由是,在bfloat16和单精度之间转换更容易


是否有任何实际的向量指令集在单精度和双精度中使用相同数量的指数位?如果是这样,它们是更接近单精度的典型8位,还是双精度的典型11位?

好吧,没有人这样做。与构建FPU执行单元的晶体管总体成本相比,符号扩展和零扩展在硬件上非常简单

与构建一个可以用作一个52位乘法器或两个单独的23位乘法器的乘法器相比,将指数位与尾数位路由到需要的位置并不是什么大问题。这样,相同的晶体管可用于压缩单乘和压缩双乘/FMA的尾数;这是FMA/倍增器单元的一大部分模具面积

顺便说一句,所有的CPU都足够现代化,可以让SIMD使用IEEE-754格式,因为这正是人们想要的,没有令人信服的理由不这样做。当然,绝大多数都使用标准格式


例如,ARM NEON最初不支持完整的IEEE 754,但他们遗漏的是逐渐低于正常值的下溢。他们仍然使用IEEE binary32和binary64标准浮点和双精度数据格式。与构建FPU执行单元的晶体管总体成本相比,符号扩展和零扩展在硬件上非常简单

与构建一个可以用作一个52位乘法器或两个单独的23位乘法器的乘法器相比,将指数位与尾数位路由到需要的位置并不是什么大问题。这样,相同的晶体管可用于压缩单乘和压缩双乘/FMA的尾数;这是FMA/倍增器单元的一大部分模具面积

顺便说一句,所有的CPU都足够现代化,可以让SIMD使用IEEE-754格式,因为这正是人们想要的,没有令人信服的理由不这样做。当然,绝大多数都使用标准格式

例如,ARM NEON最初不支持完整的IEEE 754,但他们遗漏的是逐渐低于正常值的下溢。他们仍然使用IEEE binary32和binary64标准浮点和双精度数据格式

是否有任何实际的向量指令集在单精度和双精度中使用相同数量的指数位

我不知道。然而,如果您不一定需要矢量的,x87硬件就是这样做的。硬件的位数甚至超过了双精度,内部格式是80位,它们使用15位表示指数,64位表示尾数

FPU有一个控制寄存器,用3个可能的值指定精度,32、64或80位。当设置为32位时,每条指令将尾数舍入并截断指数,使其为±INF或零

现代编译器不再发出这些指令,而是使用SSE向量寄存器的最低通道

如果偏离IEEE标准,并使两者使用相同数量的指数位,则电路设计应该更简单

是的。这正是英特尔在1980年推出8087 FPU的原因,整个芯片只有45k晶体管

然而,现代CPU有数十亿晶体管的预算。简单的设计不再是优先考虑的;性能和功耗是非常重要的

说到性能,8087最多花费200个周期来划分两个浮点数。我目前的CPU AMD Zen2一次最多花费10个周期来划分其中8个32位浮点,一次最多花费13个周期来划分其中4个64位浮点。从200个周期中获得了巨大的改进,但代价是复杂性和晶体管数量

是否有任何实际的向量指令集在单精度和双精度中使用相同数量的指数位

我不知道。然而,如果您不一定需要矢量的,x87硬件就是这样做的。房委会 rdware的位数甚至超过了双精度,内部格式是80位,它们使用15位表示指数,64位表示尾数

FPU有一个控制寄存器,用3个可能的值指定精度,32、64或80位。当设置为32位时,每条指令将尾数舍入并截断指数,使其为±INF或零

现代编译器不再发出这些指令,而是使用SSE向量寄存器的最低通道

如果偏离IEEE标准,并使两者使用相同数量的指数位,则电路设计应该更简单

是的。这正是英特尔在1980年推出8087 FPU的原因,整个芯片只有45k晶体管

然而,现代CPU有数十亿晶体管的预算。简单的设计不再是优先考虑的;性能和功耗是非常重要的


说到性能,8087最多花费200个周期来划分两个浮点数。我目前的CPU AMD Zen2一次最多花费10个周期来划分其中8个32位浮点,一次最多花费13个周期来划分其中4个64位浮点。从200个周期大幅改进,但其代价是复杂性和晶体管计数。

对于标量处理,DEC VAX最初将此方法用于其F单精度和D双精度格式;两者都使用8位指数字段。但是,在某些情况下,小指数范围会导致双精度计算的数值问题,因此后来添加了G格式(基本上是IEEE-754双精度)。@njuffa:有趣!如果你愿意的话,可以把这个问题作为答案发布出来,尽管出于某种原因,这个问题仅限于SIMD。在晶体管预算较小的时候,这对标量FPU更有意义;如果你从来不需要更宽的指数,那么你根本不需要构建它。@Peter Cordes VAX使用的方法在旧计算机中并不少见。例如,IBM System/360在单精度和双精度上都使用了基数为16的浮点格式和7位二进制指数。这个问题集中在较新的基于SIMD的体系结构上;这就是为什么我没有发布这些小信息作为答案。@njuffa我没有想到标量FPU也会出现这种情况,这就是为什么我只谈论SIMD,但你是对的,这是一个有趣的例子!对于标量处理,DEC VAX最初使用这种方法,使用F单精度和D双精度格式;两者都使用8位指数字段。但是,在某些情况下,小指数范围会导致双精度计算的数值问题,因此后来添加了G格式(基本上是IEEE-754双精度)。@njuffa:有趣!如果你愿意的话,可以把这个问题作为答案发布出来,尽管出于某种原因,这个问题仅限于SIMD。在晶体管预算较小的时候,这对标量FPU更有意义;如果你从来不需要更宽的指数,那么你根本不需要构建它。@Peter Cordes VAX使用的方法在旧计算机中并不少见。例如,IBM System/360在单精度和双精度上都使用了基数为16的浮点格式和7位二进制指数。这个问题集中在较新的基于SIMD的体系结构上;这就是为什么我没有发布这些小信息作为答案。@njuffa我没有想到标量FPU也会出现这种情况,这就是为什么我只谈论SIMD,但你是对的,这是一个有趣的例子!明确地说,x87通过在加载/存储期间转换为通用内部格式来解决问题,而不是通过实际使用单独的格式。要提供舍入到浮动或双尾数宽度,而无需存储/重新加载,精度控制设置允许您设置输出结果的舍入精度。但它仍然尊重输入的完整尾数,因此它与使用不同的格式并不完全相同。在精度设置为23位的情况下,我认为您仍然可以减去从内存中加载的两个非常接近80位的浮点值,从而得到准确的结果。减法后舍入,而不是在两个输入上舍入,忽略其尾数的低位。明确地说,x87通过在加载/存储期间转换为通用内部格式,而不是通过实际使用单独的格式来解决问题。要提供舍入到浮动或双尾数宽度,而无需存储/重新加载,精度控制设置允许您设置输出结果的舍入精度。但它仍然尊重输入的完整尾数,因此它与使用不同的格式并不完全相同。在精度设置为23位的情况下,我认为您仍然可以减去从内存中加载的两个非常接近80位的浮点值,从而得到准确的结果。减法后舍入,而不是忽略尾数的低位。