为什么在交换 long double 值中的位后得到 nan?
Why do i get nan after swapping bits in long double value?
我不得不为我的 class 编写一个程序,该程序交换一些 long double 值的二进制表示形式的 2 组位。我知道在 IEEE-754 标准中,当整个指数都填满时,nan 就会出现。但就我而言,它没有完全填满,所以我认为没有理由使用 nan。我不知道为什么会这样。我多次调试我的代码,它似乎工作正常。我认为与 char 数组和返回十进制的对话是正确的,因为当我从 main 中删除 ld_switch_chunks 函数时,程序打印出与开始时相同的数字。
#include <stdio.h>
typedef union b_long_double
{
char bin[16];
long double num;
}b_long_double;
// char array to long double conversation
void transform_to_ld(const char * in)
{
b_long_double tmp;
tmp.num=0;
for(int i=0; i<16; ++i)
tmp.bin[i] = 0;
for(int i=0; i<16; ++i)
{
char total = 0;
for(int j=0; j<8;++j)
{
char current = 0;
if(in[(i*8)+j] == 1)
{
current += 1;
current <<= j;
total |= current;
}
}
tmp.bin[i] = total;
}
printf("%Lf\n", tmp.num);
}
//splits long double value to array of chars
void split_ld_to_bin(const char* in, char* out)
{
for(int i=0; i<16; ++i)
{
char current = in[i];
for(int j=0; j<8;++j)
{
int index = i*8+j;
out[index] = current & 1;
current >>= 1;
}
}
}
//swaps 2 chunks of bits
void ld_switch_chunks(char * in)
{
int first_bit=77; //lead bit of first chunk
int second_bit=63; //lead bit of second chunk
int length=6; // length of chunk
if(first_bit < 0 || first_bit > 79)
{
printf("Invalid input\n");
return;
}
if(second_bit < 0 || second_bit > 79 || first_bit == second_bit)
{
printf("Invalid input\n");
return;
}
if(length <= 0 || length > 40 || (second_bit-length) < 0 || (first_bit-length) < 0
|| ( second_bit>first_bit && (second_bit-length) <= first_bit) || (first_bit>second_bit && (first_bit-length) <= second_bit))
{
printf("Invalid input\n");
return;
}
char tmp = 0;
if(first_bit > second_bit)
for(int i=0; i<length; ++i)
{
tmp = in[second_bit-i];
in[second_bit-i] = in[first_bit-i];
in[first_bit-i] = tmp;
}
else
for(int i=0; i<length; ++i)
{
tmp = in[first_bit-i];
in[first_bit-i] = in[second_bit-i];
in[second_bit-i] = tmp;
}
}
void print_ld(char* ld_array)
{
for(int i=79; i>=0; --i)
printf("%d", ld_array[i]);
printf("\n");
}
int main()
{
b_long_double input;
input.num = 15.375; // input number
char binary[128] = {};
split_ld_to_bin(input.bin, binary);
print_ld(binary);
ld_switch_chunks(binary);
print_ld(binary);
transform_to_ld(binary);
}
输出为:
01000000000000101111011000000000000000000000000000000000000000000000000000000000
01111101000000100000001000000000000000000000000000000000000000000000000000000000
nan
,其中第一行是初始数据的二进制,第二行是交换集的二进制,第三行必须是位交换产生的新长双精度值。
我想知道为什么会这样。
深入了解这个关于 x86 80-bit extended precision format 的维基百科页面(我认为这是 OP 搞砸的页面),我们可以找到 table 关于“x86 扩展字段的解释”精度值。
它说,关于 63 位为零(如 OP 的示例):
Unnormal. Only generated on the 8087 and 80287. The 80387 and later treat this as an invalid operand.
...
In contrast to the single and double-precision formats, this format does not utilize an implicit/hidden bit. Rather, bit 63 contains the integer part of the significand and bits 62-0 hold the fractional part. Bit 63 will be 1 on all normalized numbers.
这应该可以解释 NaN。
我不得不为我的 class 编写一个程序,该程序交换一些 long double 值的二进制表示形式的 2 组位。我知道在 IEEE-754 标准中,当整个指数都填满时,nan 就会出现。但就我而言,它没有完全填满,所以我认为没有理由使用 nan。我不知道为什么会这样。我多次调试我的代码,它似乎工作正常。我认为与 char 数组和返回十进制的对话是正确的,因为当我从 main 中删除 ld_switch_chunks 函数时,程序打印出与开始时相同的数字。
#include <stdio.h>
typedef union b_long_double
{
char bin[16];
long double num;
}b_long_double;
// char array to long double conversation
void transform_to_ld(const char * in)
{
b_long_double tmp;
tmp.num=0;
for(int i=0; i<16; ++i)
tmp.bin[i] = 0;
for(int i=0; i<16; ++i)
{
char total = 0;
for(int j=0; j<8;++j)
{
char current = 0;
if(in[(i*8)+j] == 1)
{
current += 1;
current <<= j;
total |= current;
}
}
tmp.bin[i] = total;
}
printf("%Lf\n", tmp.num);
}
//splits long double value to array of chars
void split_ld_to_bin(const char* in, char* out)
{
for(int i=0; i<16; ++i)
{
char current = in[i];
for(int j=0; j<8;++j)
{
int index = i*8+j;
out[index] = current & 1;
current >>= 1;
}
}
}
//swaps 2 chunks of bits
void ld_switch_chunks(char * in)
{
int first_bit=77; //lead bit of first chunk
int second_bit=63; //lead bit of second chunk
int length=6; // length of chunk
if(first_bit < 0 || first_bit > 79)
{
printf("Invalid input\n");
return;
}
if(second_bit < 0 || second_bit > 79 || first_bit == second_bit)
{
printf("Invalid input\n");
return;
}
if(length <= 0 || length > 40 || (second_bit-length) < 0 || (first_bit-length) < 0
|| ( second_bit>first_bit && (second_bit-length) <= first_bit) || (first_bit>second_bit && (first_bit-length) <= second_bit))
{
printf("Invalid input\n");
return;
}
char tmp = 0;
if(first_bit > second_bit)
for(int i=0; i<length; ++i)
{
tmp = in[second_bit-i];
in[second_bit-i] = in[first_bit-i];
in[first_bit-i] = tmp;
}
else
for(int i=0; i<length; ++i)
{
tmp = in[first_bit-i];
in[first_bit-i] = in[second_bit-i];
in[second_bit-i] = tmp;
}
}
void print_ld(char* ld_array)
{
for(int i=79; i>=0; --i)
printf("%d", ld_array[i]);
printf("\n");
}
int main()
{
b_long_double input;
input.num = 15.375; // input number
char binary[128] = {};
split_ld_to_bin(input.bin, binary);
print_ld(binary);
ld_switch_chunks(binary);
print_ld(binary);
transform_to_ld(binary);
}
输出为:
01000000000000101111011000000000000000000000000000000000000000000000000000000000
01111101000000100000001000000000000000000000000000000000000000000000000000000000
nan
,其中第一行是初始数据的二进制,第二行是交换集的二进制,第三行必须是位交换产生的新长双精度值。 我想知道为什么会这样。
深入了解这个关于 x86 80-bit extended precision format 的维基百科页面(我认为这是 OP 搞砸的页面),我们可以找到 table 关于“x86 扩展字段的解释”精度值。
它说,关于 63 位为零(如 OP 的示例):
Unnormal. Only generated on the 8087 and 80287. The 80387 and later treat this as an invalid operand.
...
In contrast to the single and double-precision formats, this format does not utilize an implicit/hidden bit. Rather, bit 63 contains the integer part of the significand and bits 62-0 hold the fractional part. Bit 63 will be 1 on all normalized numbers.
这应该可以解释 NaN。