对双精度浮点数组使用memset(,0,)是否合法?

时间:2021-11-03 22:34:13

Is it legal to zero array of doubles (using memset(,0,)) or struct containing doubles ?

是否合法为零双精度浮点数组(使用memset(,0,))或包含双精度浮点数的struct ?

The question implies two different things:

这个问题包含两个不同的东西:

(1) From the point of view of C standard, is this UB of not ? (on a fixed platform, how can this UB ... it just depends of floating representation that's all ...)

(1)从C标准来看,这个UB是不是?在一个固定的平台上,这个UB…这取决于浮动表示法

(2) From practical point of view: is it ok on intel platform ? (no matter what standard is saying).

(2)从实际出发:在intel平台上可以吗?(不管标准怎么说)。

7 个解决方案

#1


27  

The C99 standard Annex F says:

C99标准附件F说:

This annex specifies C language support for the IEC 60559 floating-point standard. The IEC 60559 floating-point standard is specifically Binary floating-point arithmetic for microprocessor systems, second edition (IEC 60559:1989), previously designated IEC 559:1989 and as IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE 754−1985). IEEE Standard for Radix-Independent Floating-Point Arithmetic (ANSI/IEEE 854−1987) generalizes the binary standard to remove dependencies on radix and word length. IEC 60559 generally refers to the floating-point standard, as in IEC 60559 operation, IEC 60559 format, etc. An implementation that defines __STDC_IEC_559__ shall conform to the specifications in this annex. Where a binding between the C language and IEC 60559 is indicated, the IEC 60559-specified behavior is adopted by reference, unless stated otherwise.

本附件规定了对IEC 60559浮点标准的C语言支持。IEC 60559浮点标准二进制浮点运算是专门为微处理器系统,第二版(IEC 60559:1989),先前指定的IEC 559:1989和二进制浮点运算的IEEE标准(ANSI / IEEE 754−1985)。Radix-Independent浮点运算的IEEE标准(ANSI / IEEE 854−1987)概括二进制标准删除依赖基数和字长。IEC 60559一般是指浮点标准,如IEC 60559操作、IEC 60559格式等。定义为__STDC_IEC_559__的实现应符合本附件的规范。如果指出C语言和IEC 60559之间的绑定,则引用采用IEC 605559指定的行为,除非另有说明。

And, immediately after,

后立即,

The C floating types match the IEC 60559 formats as follows:

C浮动类型匹配IEC 60559格式如下:

  • The float type matches the IEC 60559 single format.
  • 浮动类型匹配IEC 60559单一格式。
  • The double type matches the IEC 60559 double format.
  • 双类型匹配IEC 60559双格式。

So, if IEC 60559 is basically IEEE 754-1985 and this specifies that 8 zero bytes mean 0.0 (as @David Heffernan said), this means that if you find __STDC_IEC_559__ defined you can safely do a 0.0 initialization with memset.

因此,如果iec60559基本上是IEEE 754-1985,它指定了8个零字节的平均值为0.0(如@David Heffernan所说),这意味着如果您发现__STDC_IEC_559_ _定义您可以安全的使用memset进行0.0初始化。

#2


14  

If you are talking about IEEE754 then the standard defines +0.0 to double precision as 8 zero bytes. If you know that you are backed by IEEE754 floating point then this is well-defined.

如果您正在讨论IEEE754,那么标准将+0.0定义为8个零字节的双精度。如果您知道IEEE754浮点支持,那么这就是定义良好的。

As for Intel, I can't think of a compiler that doesn't use IEEE754 on Intel x86/x64.

至于英特尔,我想不出在Intel x86/x64上没有使用IEEE754的编译器。

#3


5  

David Heffernan has given a good answer for part (2) of your question. For part (1):

David Heffernan对你问题的第(2)部分给出了很好的回答。部分(1):

The C99 standard makes no guarantees about the representation of floating-point values in the general case. §6.2.6.1 says:

C99标准不保证在一般情况下浮点值的表示。§6.2.6.1说:

The representations of all types are unspecified except as stated in this subclause.

除本款所述外,所有类型的表示均未指明。

...and that subclause makes no further mention of floating point.

…这个子句没有进一步提到浮点数。

You said:

你说:

(on a fixed platform, how can this UB ... it just depends of floating representation that's all ...)

在一个固定的平台上,这个UB…这取决于浮动表示法

Indeed - there a difference between "undefined behaviour", "unspecified behaviour" and "implementation-defined behaviour":

的确,“未定义行为”、“未定义行为”和“实施定义行为”之间存在差异:

  • "undefined behaviour" means that anything could happen (including a runtime crash);
  • “未定义的行为”意味着任何可能发生的事情(包括运行时崩溃);
  • "unspecificed behaviour" means that the compiler is free to implement something sensible in any way it likes, but there is no requirement for the implementation choice to be documented;
  • “非特定行为”意味着编译器可以*地以任何它喜欢的方式实现合理的东西,但是不需要对实现选择进行文档化;
  • "implementation-defined behaviour" means that the compiler is free to implement something sensible in any way it likes, and is supposed to document that choice (for example, see here for the implementation choices documented by the most recent release of GCC);
  • “实现定义的行为”意味着编译器可以*地以任何它喜欢的方式实现一些合理的东西,并且应该记录这种选择(例如,请参阅本文中最近版本GCC所记录的实现选择);

and so, as floating point representation is unspecified behaviour, it can vary in an undocumented manner from platform to platform (where "platform" here means "the combination of hardware and compiler" rather than just "hardware").

因此,由于浮点表示是一种未指定的行为,它可以在不同平台之间以一种未文档化的方式变化(此处的“平台”表示“硬件和编译器的结合”,而不仅仅是“硬件”)。

(I'm not sure how useful the guarantee that a double is represented such that all-bits-zero is +0.0 if __STDC_IEC_559__ is defined, as described in Matteo Italia's answer, actually is in practice. For example, GCC never defines this, even though is uses IEEE 754 / IEC 60559 on many hardware platforms.)

(我不知道如果像Matteo Italia所作的答案所描述的那样,定义了__STDC_IEC_559__,那么保证双精度浮点数为0的双精度浮点数是+0.0有多大用处。例如,GCC从不定义这个,即使is在许多硬件平台上使用IEEE 754 / IEC 60559)。

#4


4  

Even though it is unlikely that you encounter a machine where this has problems, you may also avoid this relatively easily if you are really talking of arrays as you indicate in the question title, and if these arrays are of known length at compile time (that is not VLA), then just initializing them is probably even more convenient:

尽管不太可能遇到机器有问题,你也可以避免这种相对容易如果你真的说的数组表示的问题标题,如果这些已知长度的数组是在编译时(这不是VLA),然后初始化它们可能是更方便:

double A[133] = { 0 };

should always work. If you'd have to zero such an array again, later, and your compiler is compliant to modern C (C99) you can do this with a compound literal

应该工作。如果以后还需要将这样的数组归零,并且您的编译器兼容现代C (C99),那么您可以使用复合文字来实现这一点

memcpy(A, (double const[133]){ 0 }, 133*sizeof(double));

on any modern compiler this should be as efficient as memset, but has the advantage of not relying on a particular encoding of double.

在任何现代编译器上,这应该和memset一样高效,但是它的优点是不依赖双精度编码。

#5


3  

As Matteo Italia says, that's legal according to the standard, but I wouldn't use it. Something like

就像Matteo Italia所说的那样,这是符合标准的,但我不会使用它。类似的

double *p = V, *last = V + N; // N - count
while(p != last) *(p++) = 0;

is at least twice faster.

至少要快两倍。

#6


0  

Well, I think the zeroing is "legal" (after all, it's zeroing a regular buffer), but I have no idea if the standard lets you assume anything about the resulting logical value. My guess would be that the C standard leaves it as undefined.

嗯,我认为归零是“合法的”(毕竟,它是一个常规的缓冲区),但是我不知道这个标准是否允许你对产生的逻辑值做任何假设。我的猜测是C标准没有定义它。

#7


0  

It's "legal" to use memset. The issue is whether it produces a bit pattern where array[x] == 0.0 is true. While the basic C standard doesn't require that to be true, I'd be interested in hearing examples where it isn't!

使用memset是合法的。问题是它是否产生一个数组[x] = 0.0为真的位模式。虽然基本的C标准并不要求它是正确的,但是我很有兴趣听到它不正确的例子!

It appears memset is equivalent to 0.0 on IBM-AIX, HP-UX (PARISC), HP-UX (IA-64), Linux (IA-64, I think).

似乎memset在IBM-AIX、HP-UX (PARISC)、HP-UX (IA-64)、Linux(我想是IA-64)上的值都是0。

    {
    double dFloat1 = 0.0;
    double dFloat2 = 111111.1111111;

    memset(&dFloat2, 0, sizeof(dFloat2));

    if(dFloat1 == dFloat2)
    {
        fprintf(stdout, "memset appears to be equivalent to = 0.0\n");
    }
    else
    {
        fprintf(stdout, "memset is NOT equivalent to = 0.0\n");
    }
}

#1


27  

The C99 standard Annex F says:

C99标准附件F说:

This annex specifies C language support for the IEC 60559 floating-point standard. The IEC 60559 floating-point standard is specifically Binary floating-point arithmetic for microprocessor systems, second edition (IEC 60559:1989), previously designated IEC 559:1989 and as IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE 754−1985). IEEE Standard for Radix-Independent Floating-Point Arithmetic (ANSI/IEEE 854−1987) generalizes the binary standard to remove dependencies on radix and word length. IEC 60559 generally refers to the floating-point standard, as in IEC 60559 operation, IEC 60559 format, etc. An implementation that defines __STDC_IEC_559__ shall conform to the specifications in this annex. Where a binding between the C language and IEC 60559 is indicated, the IEC 60559-specified behavior is adopted by reference, unless stated otherwise.

本附件规定了对IEC 60559浮点标准的C语言支持。IEC 60559浮点标准二进制浮点运算是专门为微处理器系统,第二版(IEC 60559:1989),先前指定的IEC 559:1989和二进制浮点运算的IEEE标准(ANSI / IEEE 754−1985)。Radix-Independent浮点运算的IEEE标准(ANSI / IEEE 854−1987)概括二进制标准删除依赖基数和字长。IEC 60559一般是指浮点标准,如IEC 60559操作、IEC 60559格式等。定义为__STDC_IEC_559__的实现应符合本附件的规范。如果指出C语言和IEC 60559之间的绑定,则引用采用IEC 605559指定的行为,除非另有说明。

And, immediately after,

后立即,

The C floating types match the IEC 60559 formats as follows:

C浮动类型匹配IEC 60559格式如下:

  • The float type matches the IEC 60559 single format.
  • 浮动类型匹配IEC 60559单一格式。
  • The double type matches the IEC 60559 double format.
  • 双类型匹配IEC 60559双格式。

So, if IEC 60559 is basically IEEE 754-1985 and this specifies that 8 zero bytes mean 0.0 (as @David Heffernan said), this means that if you find __STDC_IEC_559__ defined you can safely do a 0.0 initialization with memset.

因此,如果iec60559基本上是IEEE 754-1985,它指定了8个零字节的平均值为0.0(如@David Heffernan所说),这意味着如果您发现__STDC_IEC_559_ _定义您可以安全的使用memset进行0.0初始化。

#2


14  

If you are talking about IEEE754 then the standard defines +0.0 to double precision as 8 zero bytes. If you know that you are backed by IEEE754 floating point then this is well-defined.

如果您正在讨论IEEE754,那么标准将+0.0定义为8个零字节的双精度。如果您知道IEEE754浮点支持,那么这就是定义良好的。

As for Intel, I can't think of a compiler that doesn't use IEEE754 on Intel x86/x64.

至于英特尔,我想不出在Intel x86/x64上没有使用IEEE754的编译器。

#3


5  

David Heffernan has given a good answer for part (2) of your question. For part (1):

David Heffernan对你问题的第(2)部分给出了很好的回答。部分(1):

The C99 standard makes no guarantees about the representation of floating-point values in the general case. §6.2.6.1 says:

C99标准不保证在一般情况下浮点值的表示。§6.2.6.1说:

The representations of all types are unspecified except as stated in this subclause.

除本款所述外,所有类型的表示均未指明。

...and that subclause makes no further mention of floating point.

…这个子句没有进一步提到浮点数。

You said:

你说:

(on a fixed platform, how can this UB ... it just depends of floating representation that's all ...)

在一个固定的平台上,这个UB…这取决于浮动表示法

Indeed - there a difference between "undefined behaviour", "unspecified behaviour" and "implementation-defined behaviour":

的确,“未定义行为”、“未定义行为”和“实施定义行为”之间存在差异:

  • "undefined behaviour" means that anything could happen (including a runtime crash);
  • “未定义的行为”意味着任何可能发生的事情(包括运行时崩溃);
  • "unspecificed behaviour" means that the compiler is free to implement something sensible in any way it likes, but there is no requirement for the implementation choice to be documented;
  • “非特定行为”意味着编译器可以*地以任何它喜欢的方式实现合理的东西,但是不需要对实现选择进行文档化;
  • "implementation-defined behaviour" means that the compiler is free to implement something sensible in any way it likes, and is supposed to document that choice (for example, see here for the implementation choices documented by the most recent release of GCC);
  • “实现定义的行为”意味着编译器可以*地以任何它喜欢的方式实现一些合理的东西,并且应该记录这种选择(例如,请参阅本文中最近版本GCC所记录的实现选择);

and so, as floating point representation is unspecified behaviour, it can vary in an undocumented manner from platform to platform (where "platform" here means "the combination of hardware and compiler" rather than just "hardware").

因此,由于浮点表示是一种未指定的行为,它可以在不同平台之间以一种未文档化的方式变化(此处的“平台”表示“硬件和编译器的结合”,而不仅仅是“硬件”)。

(I'm not sure how useful the guarantee that a double is represented such that all-bits-zero is +0.0 if __STDC_IEC_559__ is defined, as described in Matteo Italia's answer, actually is in practice. For example, GCC never defines this, even though is uses IEEE 754 / IEC 60559 on many hardware platforms.)

(我不知道如果像Matteo Italia所作的答案所描述的那样,定义了__STDC_IEC_559__,那么保证双精度浮点数为0的双精度浮点数是+0.0有多大用处。例如,GCC从不定义这个,即使is在许多硬件平台上使用IEEE 754 / IEC 60559)。

#4


4  

Even though it is unlikely that you encounter a machine where this has problems, you may also avoid this relatively easily if you are really talking of arrays as you indicate in the question title, and if these arrays are of known length at compile time (that is not VLA), then just initializing them is probably even more convenient:

尽管不太可能遇到机器有问题,你也可以避免这种相对容易如果你真的说的数组表示的问题标题,如果这些已知长度的数组是在编译时(这不是VLA),然后初始化它们可能是更方便:

double A[133] = { 0 };

should always work. If you'd have to zero such an array again, later, and your compiler is compliant to modern C (C99) you can do this with a compound literal

应该工作。如果以后还需要将这样的数组归零,并且您的编译器兼容现代C (C99),那么您可以使用复合文字来实现这一点

memcpy(A, (double const[133]){ 0 }, 133*sizeof(double));

on any modern compiler this should be as efficient as memset, but has the advantage of not relying on a particular encoding of double.

在任何现代编译器上,这应该和memset一样高效,但是它的优点是不依赖双精度编码。

#5


3  

As Matteo Italia says, that's legal according to the standard, but I wouldn't use it. Something like

就像Matteo Italia所说的那样,这是符合标准的,但我不会使用它。类似的

double *p = V, *last = V + N; // N - count
while(p != last) *(p++) = 0;

is at least twice faster.

至少要快两倍。

#6


0  

Well, I think the zeroing is "legal" (after all, it's zeroing a regular buffer), but I have no idea if the standard lets you assume anything about the resulting logical value. My guess would be that the C standard leaves it as undefined.

嗯,我认为归零是“合法的”(毕竟,它是一个常规的缓冲区),但是我不知道这个标准是否允许你对产生的逻辑值做任何假设。我的猜测是C标准没有定义它。

#7


0  

It's "legal" to use memset. The issue is whether it produces a bit pattern where array[x] == 0.0 is true. While the basic C standard doesn't require that to be true, I'd be interested in hearing examples where it isn't!

使用memset是合法的。问题是它是否产生一个数组[x] = 0.0为真的位模式。虽然基本的C标准并不要求它是正确的,但是我很有兴趣听到它不正确的例子!

It appears memset is equivalent to 0.0 on IBM-AIX, HP-UX (PARISC), HP-UX (IA-64), Linux (IA-64, I think).

似乎memset在IBM-AIX、HP-UX (PARISC)、HP-UX (IA-64)、Linux(我想是IA-64)上的值都是0。

    {
    double dFloat1 = 0.0;
    double dFloat2 = 111111.1111111;

    memset(&dFloat2, 0, sizeof(dFloat2));

    if(dFloat1 == dFloat2)
    {
        fprintf(stdout, "memset appears to be equivalent to = 0.0\n");
    }
    else
    {
        fprintf(stdout, "memset is NOT equivalent to = 0.0\n");
    }
}