根据this documentation,我的任务是根据字母数字识别器计算颜色值。我们的想法是通过SHA-1运行标识符字符串,并使用结果的一部分来计算颜色值。
我在执行以下步骤时遇到了问题:
将输出视为小端,并提取最后有效的16位。 (这是输出的前两个字节,第二个字节是最重要的字节。)
这是我到目前为止所拥有的:
double get_CbCr_angle(const char* identifier) {
unsigned char temp[SHA_DIGEST_LENGTH];
char buf[SHA_DIGEST_LENGTH*2];
// initalise with 0s
memset(buf, 0x0, SHA_DIGEST_LENGTH*2);
memset(temp, 0x0, SHA_DIGEST_LENGTH);
// compute hash into temp
SHA1((unsigned char *)identifier, strlen(identifier), temp);
// print from temp into buf and
// interpret as (signed) chars
int i = 0;
for (i=0; i < SHA_DIGEST_LENGTH; i++) {
sprintf( (char*) &(buf[i*2]), "%02x", temp[i]);
}
printf("SHA1 is %s\n", buf);
// make a union type of char and float so we can read a char array
// as float.
union charFloat {
float f;
char s[sizeof(float)];
};
union charFloat foo;
// put first two chars (bytes) into union.
// bracket notation should be fine since both foo and buf are
// char arrays.
foo.s[0] = buf[1];
foo.s[1] = buf[0];
printf("interpreted as chars: %s\n", foo.s);
printf("interpreted as float: %f\n", foo.f); // 0.000000 - why?
}
但是这种方法无法获得任何合理的输出。使用更多字节只会为float
提供无意义的值,以及将其解释为int
。
显然我不希望有人为我解决这个问题。我非常感谢一些方向的提示。
提前多多感谢。
答案 0 :(得分:4)
让我们仔细看看这个算法:
- 通过SHA-1(RFC 3174 [4])运行输入。
- 将输出视为小端,并提取最后有效的16位。 (这是输出的前两个字节,第二个 字节是最重要的一个。)
- 将值除以65536(使用浮点除法)并乘以2π(两个Pi)。
醇>
该算法并未将前两个字节视为浮点值。它表示将它们视为16位整数,然后将该值转换为浮点类型以用于下一步。
此外,转换值时,您应该使用temp
而不是buf
,因为buf
包含代表哈希输出的可打印字符,而temp
包含实际输出。 / p>
所以你要转换这样的值:
uint16_t value;
value = temp[0];
value |= temp[1] << 8;
然后将其投射到double
以进行下一步:
double result = value * 2 * M_PI / 65536;
答案 1 :(得分:3)
我会通过使用显式移位和OR从两个uint16_t
组合char
来实现此目的:
uint16_t x = (((uint16_t)(uint8_t)temp[1]) << 8) |
(((uint18_t)(uint8_t)temp[0]) << 0);
双重演员必须确保每个char
值为零,而不是在班次之前符号扩展到uint16_t
的宽度。另请注意,我正在阅读temp
,而不是buf
- 原始 SHA哈希,而不是十六进制编码哈希。使用十六进制编码的哈希将限制x
可能采用的值。
然后,将x
转换为[0, 1)
范围内的浮点数除以65536:
double f = x / 65536.0;
65536是2 16 ; uint16_t
的值范围是0到65535,包括0和65535。除数上的.0
后缀是使C执行浮点而不是整数除法所必需的。为了提高效率,这种划分可以与下一步乘以2π结合起来:
double f = x * (2 * M_PI / 65536);
M_PI
(在math.h
中声明)已经是一个浮点数,所以我们不再需要65536上的.0
后缀,但是你需要在整个子表达式周围加上括号2 * M_PI / 65536
强制编译器在编译时评估该部分,并仅发出一次运行时乘法。