C++ SHA-256双小数部分的十六进制表示法
我正在尝试编写一个SHA-256哈希函数以供练习。在这种情况下,初始散列值由前8个素数2..19的平方根的分数部分给出。现在我正在计算它们。到目前为止我所做的:C++ SHA-256双小数部分的十六进制表示法,c++,sha,fractions,C++,Sha,Fractions,我正在尝试编写一个SHA-256哈希函数以供练习。在这种情况下,初始散列值由前8个素数2..19的平方根的分数部分给出。现在我正在计算它们。到目前为止我所做的: #include <vector> #include <cstdint> #include <cmath> #include <cstdio> // fill primes with all prime values between min and max value int getPr
#include <vector>
#include <cstdint>
#include <cmath>
#include <cstdio>
// fill primes with all prime values between min and max value
int getPrimes(uint32_t min, uint32_t max, std::vector<uint32_t>* primes)
{
if (min < 1) min = 1; // primes can only be >= 1
if (min > max) return 0; // max has to be larger than min
for (uint32_t value = min; value <= max; value++)
{
uint32_t tmp;
for (tmp = 2; tmp <= sqrt(value); tmp++) // start to check with 2, because 1 is always going to work
{
if (value % tmp == 0)
{
break;
}
}
if (tmp > sqrt(value)) primes->push_back(value); // if no other integer divisor is found, add number to vector
}
return 0;
}
int main()
{
std::vector<uint32_t> primes;
getPrimes(2, 20, &primes); // fills vector with all prime values between 2 and 20
double tmp = sqrt(primes[0]); // get square root, returns double
printf("value %f\n", tmp); // debug
printf("size of double %i\n", sizeof(double)); // get representation byte size
double * tmpOffset = &tmp; // get value offset
unsigned char * tmpChar = (unsigned char*)tmpOffset; // convert to char pointer
printf("address of variable %i\n", &tmp); // debug
printf("raw values\n1:%X\n2:%X\n3:%X\n4:%X\n5:%X\n6:%X\n7:%X\n8:%X\n",
(uint8_t)tmpChar[0], (uint8_t)tmpChar[1], (uint8_t)tmpChar[2], (uint8_t)tmpChar[3],
(uint8_t)tmpChar[4], (uint8_t)tmpChar[5], (uint8_t)tmpChar[6], (uint8_t)tmpChar[7]);
return 0;
}
与维基百科文章0x6a09e667
中给出的值相比,我在这里所做的看起来大错特错。是否发生了重映射,或者双精度的二进制重表示有多精确?有人能给我指出正确的方向吗?如何正确计算十六进制的小数部分
编辑:
谢谢你的帮助!这并不漂亮,但目前确实有效
printf("raw fractional part:\n0x%02X %02X %02X %02X %02X %02X %02X\n",
(uint8_t)(0xf & tmpChar[6]), (uint8_t)tmpChar[5], (uint8_t)tmpChar[4], (uint8_t)tmpChar[3],
(uint8_t)tmpChar[2], (uint8_t)tmpChar[1], (uint8_t)tmpChar[0]);
uint32_t fracPart = (0xf & tmpChar[6]);
fracPart <<= 8;
fracPart |= tmpChar[5];
fracPart <<= 8;
fracPart |= tmpChar[4] ;
fracPart <<= 8;
fracPart |= tmpChar[3];
fracPart <<= 4;
fracPart |= (0xf0 & tmpChar[2]) >> 4;
printf("fractional part: %X\n", fracPart);
printf(“原始小数部分:\n0x%02X%02X%02X%02X%02X%02X%02X\n”,
(uint8_t)(0xf&tmpChar[6]),(uint8_t)tmpChar[5],(uint8_t)tmpChar[4],(uint8_t)tmpChar[3],
(uint8_t)tmpChar[2],(uint8_t)tmpChar[1],(uint8_t)tmpChar[0];
uint32_t fracPart=(0xf&tmpChar[6]);
fracPart需要记住的一件事是这里的双精度是64位。
如果您查看下面链接中双精度的IEEE表示,它有1个符号位、11个指数位,其余为精度位
现在,当你看一下你得到的输出,看看我在引号中加上的零头,它们看起来熟悉吗?
数字倒排的原因是因为endianness。在这种情况下,第12位是小数部分开始的位置,然后它向后移动
1:CD
2:3B
3:'7'F
4:'66'
5:'9E'
6:'A0'
7:F'6'
8:3F
或
正如您所怀疑的,double和float的二进制表示并没有那么简单。我建议用数学方法创建十六进制字符串,而不是在字节和可疑的指针类型转换中乱搞。(重复乘以16得到整数部分)0x6a09e667表示√2是1.6a09e667…₁₆ 十六进制,读double
不是这样表示的。阅读
uint32_t fracPart2 = *(uint32_t*)((char*)&tmp + 3); // point to fractional part - 4 bit
fracPart2 <<= 4; // shift to correct value
fracPart2 |= (0xf0 & *((char*)&tmp + 2)) >> 4; // append last 4 bit
printf("beautiful fractional part: %X\n", fracPart2);
uint32_t getFractionalPart(double value)
{
uint32_t retValue = 0;
for (uint8_t i = 0; i < 8; i++)
{
value = value - floor(value);
retValue <<= 4;
value *= 16;
retValue += floor(value);
}
return retValue;
}
1:CD
2:3B
3:'7'F
4:'66'
5:'9E'
6:'A0'
7:F'6'
8:3F
8:3F
7:F'6'
6:'A0'
5:'9E'
4:'66'
3:'7'F
2:3B
1:CD