floating-point - 如果一个
我正在使用一些加密库和零知识证明做一些事情,而我正在使用的库仅支持整数。
如果我有两个数字存储为双精度浮点数,我将每个数字的位复制到一
问题描述
我正在使用一些加密库和零知识证明做一些事情,而我正在使用的库仅支持整数。
如果我有两个数字存储为双精度浮点数,我将每个数字的位复制到一个整数中,然后比较整数将。
A_Double>B_Double==A_UINT>B_UINT
对于所有值。
我的猜测是它可能适用于所有正值,但不适用于负值。
虽然如果我翻转第一位可能会起作用。
您没有说明使用的浮点格式。IEEE 754 和大多数浮点系统使用一种有效的符号和大小格式。最高有效位的位是符号位。取反值是通过翻转符号位来完成的。相反,对二进制补码格式的值取反是通过翻转所有位并加一来完成的。
浮点格式通常在符号位之后是表示值的下一个最高有效位、指数位,然后是有效位。这样做的结果是,对于两个正浮点数x和y,x > y等价于 x > y,其中 x 和 y 是将 x 和 y 的位重新解释为无符号整数或二进制补码整数。但是,对于两个负浮点数,x > y等价于 x < y,无论是无符号数还是二进制补码。
此外,浮点格式通常具有非数值,称为 NaN。使用这些值,整数比较会失败,因为浮点比较被定义为对于所有比较都是错误的 - NaN 不小于、等于或大于数字或 NaN。
总之,您通常不希望使用整数解释来比较浮点值。
解决方案
在接近的轨道上
有很多关于浮点编码的假设:
当a < 0
翻转value的整数版本时,在 0脚注处折叠,因此 +0.0 和 -0.0 比较相等。FP 值通常被编码为sign-magnitude。
还要寻找 Nan 编码。
交流解决方案
#include <stdint.h>
#include <stdlib.h>
_Static_assert(sizeof(int64) == sizeof(double), "Unexpected sizes");
#define INT_NAN_TEST(a) (llabs(a) > 0x7FF0000000000000u)
/*
* Compare 2 integers as is they overlay a same size, same endian 64-bit `double`.
* Return -1,0,1 when they compare a > b, a===b, a< b
* or `'?` for un-comparable as at least one of `a,b` is NaN
*
* This code assumes a lot about the representation of a `double`.
* Same size
* Same endian
* FP with leading sign bit, then a biased exponent, then significand
*/
int cmp_double(int64_t a, int64_t b) {
if (a < 0) {
a = 0x8000000000000000 - a;
}
if (b < 0) {
b = 0x8000000000000000 - b;
}
if (INT_NAN_TEST(a) || INT_NAN_TEST(b))
return '?';
return (a > b) - (a < b);
}
测试
#include <stdlib.h>
#include <stdio.h>
#include <float.h>
#include <limits.h>
#include <string.h>
#include <math.h>
int main() {
const double d[] = {0.0, DBL_TRUE_MIN, DBL_MIN, 1, DBL_MAX, INFINITY, -0.0,
-DBL_TRUE_MIN, -DBL_MIN, -1, -DBL_MAX, -INFINITY, NAN};
size_t n = sizeof d / sizeof *d;
for (size_t i = 0; i < n; i++) {
double a = d[i];
int64_t ai;
memcpy(&ai, &a, sizeof ai);
for (size_t bb = 0; bb < n; bb++) {
double b = d[bb];
int64_t bi;
memcpy(&bi, &b, sizeof bi);
int cmp_d = (isnan(a) || isnan(b)) ? '?' : (a > b) - (a < b);
int cmp_i = cmp_double(ai, bi);
if (cmp_d != cmp_i) {
printf("% 20g %16llX % 20g %16llX: %2d %2d\n", a, 1llu * ai, b,
1llu * bi, cmp_d, cmp_i);
}
}
}
puts("Done");
}
脚注通过折叠负数使 0000_0000_0000_0000 和 8000_0000_0000_0000 都是“零”,最负的“作为整数的双精度数”值将比最负的可编码整数多 1,从而防止 UB 在llabs()
计算中。
推荐阅读
- c# - 当输出是数组时如何将matlab转换为c#?
- c# - 在 SQL 数据库的 Entity Framework Core 模型中实现加密
- swift - SwiftUI 中的轮播/侧边栏列表样式
- php - 当用户在@ key textarea字段中键入时如何显示评论用户的列表
- node.js - 尽管用户已保存在数据库中,但我收到 401“未经授权”错误
- saml - 使用 simplesaml 为响应添加自定义属性
- c++ - istream 未完全恢复已放入 stringstream 的内容
- sql - 用于将多个变量计数为“Both”的 SQL 函数
- c++ - 使用箭头键移动
- javascript - ES6 函数后面的方括号有什么作用?
我正在使用一些加密库和零知识证明做一些事情,而我正在使用的库仅支持整数。
如果我有两个数字存储为双精度浮点数,我将每个数字的位复制到一
问题描述
我正在使用一些加密库和零知识证明做一些事情,而我正在使用的库仅支持整数。
如果我有两个数字存储为双精度浮点数,我将每个数字的位复制到一个整数中,然后比较整数将。
A_Double>B_Double==A_UINT>B_UINT
对于所有值。
我的猜测是它可能适用于所有正值,但不适用于负值。
虽然如果我翻转第一位可能会起作用。
您没有说明使用的浮点格式。IEEE 754 和大多数浮点系统使用一种有效的符号和大小格式。最高有效位的位是符号位。取反值是通过翻转符号位来完成的。相反,对二进制补码格式的值取反是通过翻转所有位并加一来完成的。
浮点格式通常在符号位之后是表示值的下一个最高有效位、指数位,然后是有效位。这样做的结果是,对于两个正浮点数x和y,x > y等价于 x > y,其中 x 和 y 是将 x 和 y 的位重新解释为无符号整数或二进制补码整数。但是,对于两个负浮点数,x > y等价于 x < y,无论是无符号数还是二进制补码。
此外,浮点格式通常具有非数值,称为 NaN。使用这些值,整数比较会失败,因为浮点比较被定义为对于所有比较都是错误的 - NaN 不小于、等于或大于数字或 NaN。
总之,您通常不希望使用整数解释来比较浮点值。
在接近的轨道上
有很多关于浮点编码的假设:
当a < 0
翻转value的整数版本时,在 0脚注处折叠,因此 +0.0 和 -0.0 比较相等。FP 值通常被编码为sign-magnitude。
还要寻找 Nan 编码。
交流解决方案
#include <stdint.h>
#include <stdlib.h>
_Static_assert(sizeof(int64) == sizeof(double), "Unexpected sizes");
#define INT_NAN_TEST(a) (llabs(a) > 0x7FF0000000000000u)
/*
* Compare 2 integers as is they overlay a same size, same endian 64-bit `double`.
* Return -1,0,1 when they compare a > b, a===b, a< b
* or `'?` for un-comparable as at least one of `a,b` is NaN
*
* This code assumes a lot about the representation of a `double`.
* Same size
* Same endian
* FP with leading sign bit, then a biased exponent, then significand
*/
int cmp_double(int64_t a, int64_t b) {
if (a < 0) {
a = 0x8000000000000000 - a;
}
if (b < 0) {
b = 0x8000000000000000 - b;
}
if (INT_NAN_TEST(a) || INT_NAN_TEST(b))
return '?';
return (a > b) - (a < b);
}
测试
#include <stdlib.h>
#include <stdio.h>
#include <float.h>
#include <limits.h>
#include <string.h>
#include <math.h>
int main() {
const double d[] = {0.0, DBL_TRUE_MIN, DBL_MIN, 1, DBL_MAX, INFINITY, -0.0,
-DBL_TRUE_MIN, -DBL_MIN, -1, -DBL_MAX, -INFINITY, NAN};
size_t n = sizeof d / sizeof *d;
for (size_t i = 0; i < n; i++) {
double a = d[i];
int64_t ai;
memcpy(&ai, &a, sizeof ai);
for (size_t bb = 0; bb < n; bb++) {
double b = d[bb];
int64_t bi;
memcpy(&bi, &b, sizeof bi);
int cmp_d = (isnan(a) || isnan(b)) ? '?' : (a > b) - (a < b);
int cmp_i = cmp_double(ai, bi);
if (cmp_d != cmp_i) {
printf("% 20g %16llX % 20g %16llX: %2d %2d\n", a, 1llu * ai, b,
1llu * bi, cmp_d, cmp_i);
}
}
}
puts("Done");
}
脚注通过折叠负数使 0000_0000_0000_0000 和 8000_0000_0000_0000 都是“零”,最负的“作为整数的双精度数”值将比最负的可编码整数多 1,从而防止 UB 在llabs()
计算中。