Skip to content

Commit b115c64

Browse files
committed
fix(random): remove double conversions and std::floor in DeterministicNormalDistribution
1 parent 388fb9e commit b115c64

4 files changed

Lines changed: 22 additions & 29 deletions

File tree

‎cpp/deglib/include/random.h‎

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace deglib::random {
2727
namespace detail {
2828

2929
// Portable float natural logarithm (log(x)) without platform libm dependencies.
30-
// Accurate to 1e-7 (full float precision) across [1e-38, 1e38].
30+
// Operates strictly on 32-bit floats with 24-bit mantissa precision.
3131
inline float portable_log(float x) {
3232
uint32_t ix;
3333
std::memcpy(&ix, &x, sizeof(float));
@@ -48,16 +48,11 @@ inline float portable_log(float x) {
4848
}
4949

5050
// Portable float cosine (cos(x)) without platform libm dependencies.
51-
// Uses symmetry reduction to [0, PI/2] and a 10th-degree polynomial for full float precision (1e-7).
51+
// Input x is in [0, 2*PI). Uses symmetry reduction to [0, PI/2] and a 10th-degree polynomial.
5252
inline float portable_cos(float x) {
53-
constexpr float TWO_PI = 6.28318530717958647692f;
5453
constexpr float PI = 3.14159265358979323846f;
5554
constexpr float HALF_PI = 1.57079632679489661923f;
56-
constexpr float INV_TWO_PI = 0.15915494309189533576f;
57-
58-
// Reduce x to [0, 2*PI)
59-
x -= std::floor(x * INV_TWO_PI) * TWO_PI;
60-
if (x < 0.0f) x += TWO_PI;
55+
constexpr float TWO_PI = 6.28318530717958647692f;
6156

6257
// Symmetry reduction to [0, PI]
6358
if (x > PI) {
@@ -71,7 +66,7 @@ inline float portable_cos(float x) {
7166
sign = true;
7267
}
7368

74-
// Polynomial for cos(x) on [0, PI/2] accurate to 1e-7
69+
// Polynomial for cos(x) on [0, PI/2] accurate to 1e-7 (full float precision)
7570
float x2 = x * x;
7671
float res = 1.0f - x2 * (0.5f - x2 * (0.041666666666666664f - x2 * (0.0013888888888888889f - x2 * (0.0000248015873015873f - x2 * 0.000000275573192239859f))));
7772

@@ -127,22 +122,20 @@ class DeterministicNormalDistribution {
127122
: mean_(mean), stddev_(stddev) {}
128123

129124
// Generate a single normally-distributed float using the provided RNG.
130-
// Always consumes exactly 2 RNG values per call (no caching/spare state)
131-
// to ensure deterministic behavior regardless of how multiple
132-
// DeterministicNormalDistribution instances share the same RNG.
125+
// Operates strictly on 24-bit mantissa float division and portable math
126+
// to guarantee 100% bit-identical sequences across Windows, Linux, and macOS.
133127
float operator()(std::mt19937& rng) {
134-
// Box-Muller transform: generate one standard normal from two uniforms.
135-
// We discard the second value (z1) to avoid cross-instance state issues.
136128
float u1, u2;
137129
do {
138-
u1 = static_cast<float>(static_cast<double>(rng()) / (static_cast<double>(rng.max()) + 1.0));
130+
uint32_t v1 = rng() >> 8;
131+
u1 = static_cast<float>(v1) / 16777216.0f;
139132
} while (u1 <= 0.0f);
140-
u2 = static_cast<float>(static_cast<double>(rng()) / (static_cast<double>(rng.max()) + 1.0));
141133

142-
// Box-Muller formula: z0 = sqrt(-2 * ln(u1)) * cos(2 * pi * u2)
143-
// Uses portable_log and portable_cos to avoid platform-dependent libm differences.
134+
uint32_t v2 = rng() >> 8;
135+
u2 = static_cast<float>(v2) / 16777216.0f;
136+
144137
float mag = stddev_ * std::sqrt(-2.0f * detail::portable_log(u1));
145-
return mean_ + mag * detail::portable_cos(2.0f * 3.14159265358979323846f * u2);
138+
return mean_ + mag * detail::portable_cos(6.28318530717958647692f * u2);
146139
}
147140

148141
private:

‎cpp/test/src/regression/builder/test_l2_builder_regression.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ TEST(DeglibBuilderRegressionL2, Benchmark_LowLID)
1717

1818
auto gt_data = compute_groundtruth_l2(base_data, base_count, query_data, query_count, dim, 10);
1919

20-
run_regression_test("LowLID", deglib::Metric::L2, 30000.0, 9.3, 0.94,
20+
run_regression_test("LowLID", deglib::Metric::L2, 30000.0, 9.3, 0.99,
2121
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
2222
deglib::distances::fp32_l2::L2Float{}, 100,
2323
deglib::builder::OptimizationTarget::LowLID);
@@ -36,7 +36,7 @@ TEST(DeglibBuilderRegressionL2, Benchmark_HighLID)
3636

3737
auto gt_data = compute_groundtruth_l2(base_data, base_count, query_data, query_count, dim, 10);
3838

39-
run_regression_test("HighLID", deglib::Metric::L2, 16000.0, 10.0, 0.867,
39+
run_regression_test("HighLID", deglib::Metric::L2, 16000.0, 10.0, 0.918,
4040
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
4141
deglib::distances::fp32_l2::L2Float{}, 100,
4242
deglib::builder::OptimizationTarget::HighLID);
@@ -55,7 +55,7 @@ TEST(DeglibBuilderRegressionL2, Benchmark_StreamingData)
5555

5656
auto gt_data = compute_groundtruth_l2(base_data, base_count, query_data, query_count, dim, 10);
5757

58-
run_regression_test("StreamingData", deglib::Metric::L2, 23000.0, 23.8, 0.93,
58+
run_regression_test("StreamingData", deglib::Metric::L2, 23000.0, 23.8, 0.95,
5959
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
6060
deglib::distances::fp32_l2::L2Float{}, 100,
6161
deglib::builder::OptimizationTarget::StreamingData);

‎cpp/test/src/regression/metric/test_innerproduct_regression.cpp‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ TEST(DeglibRegressionIP, Benchmark_AVX512_16Ext)
1717

1818
auto gt_data = compute_groundtruth_innerproduct(base_data, base_count, query_data, query_count, dim, 10);
1919

20-
run_regression_test("AVX512_16Ext", deglib::Metric::InnerProduct, 18000.0, 10.3, 0.79,
20+
run_regression_test("AVX512_16Ext", deglib::Metric::InnerProduct, 18000.0, 10.3, 0.78,
2121
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
2222
deglib::distances::fp32_ip::InnerProductFloat16Ext_AVX512{}, 50);
2323
#else
@@ -42,7 +42,7 @@ TEST(DeglibRegressionIP, Benchmark_AVX2_16Ext)
4242

4343
auto gt_data = compute_groundtruth_innerproduct(base_data, base_count, query_data, query_count, dim, 10);
4444

45-
run_regression_test("AVX2_16Ext", deglib::Metric::InnerProduct, 18000.0, 10.3, 0.79,
45+
run_regression_test("AVX2_16Ext", deglib::Metric::InnerProduct, 18000.0, 10.3, 0.78,
4646
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
4747
deglib::distances::fp32_ip::InnerProductFloat16Ext_AVX2{}, 50);
4848
#else
@@ -67,7 +67,7 @@ TEST(DeglibRegressionIP, Benchmark_SSE_16Ext)
6767

6868
auto gt_data = compute_groundtruth_innerproduct(base_data, base_count, query_data, query_count, dim, 10);
6969

70-
run_regression_test("SSE_16Ext", deglib::Metric::InnerProduct, 16000.0, 11.8, 0.78,
70+
run_regression_test("SSE_16Ext", deglib::Metric::InnerProduct, 16000.0, 11.8, 0.82,
7171
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
7272
deglib::distances::fp32_ip::InnerProductFloat16Ext_SSE{}, 50);
7373
#else
@@ -88,7 +88,7 @@ TEST(DeglibRegressionIP, Benchmark_Scalar)
8888

8989
auto gt_data = compute_groundtruth_innerproduct(base_data, base_count, query_data, query_count, dim, 10);
9090

91-
run_regression_test("Scalar", deglib::Metric::InnerProduct, 13500.0, 15.8, 0.82,
91+
run_regression_test("Scalar", deglib::Metric::InnerProduct, 13500.0, 15.8, 0.8,
9292
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
9393
deglib::distances::fp32_ip::InnerProductFloat{}, 50);
9494
}

‎cpp/test/src/regression/metric/test_l2_regression.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ TEST(DeglibRegressionL2, Benchmark_AVX512_16Ext)
1717

1818
auto gt_data = compute_groundtruth_l2(base_data, base_count, query_data, query_count, dim, 10);
1919

20-
run_regression_test("AVX512_16Ext", deglib::Metric::L2, 42000.0, 6.0, 0.949,
20+
run_regression_test("AVX512_16Ext", deglib::Metric::L2, 42000.0, 6.0, 0.94,
2121
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
2222
deglib::distances::fp32_l2::L2Float16Ext_AVX512{}, 100);
2323
#else
@@ -67,7 +67,7 @@ TEST(DeglibRegressionL2, Benchmark_SSE_16Ext)
6767

6868
auto gt_data = compute_groundtruth_l2(base_data, base_count, query_data, query_count, dim, 10);
6969

70-
run_regression_test("SSE_16Ext", deglib::Metric::L2, 33000.0, 7.0, 0.979,
70+
run_regression_test("SSE_16Ext", deglib::Metric::L2, 33000.0, 7.0, 0.93,
7171
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
7272
deglib::distances::fp32_l2::L2Float16Ext_SSE{}, 100);
7373
#else
@@ -88,7 +88,7 @@ TEST(DeglibRegressionL2, Benchmark_Scalar)
8888

8989
auto gt_data = compute_groundtruth_l2(base_data, base_count, query_data, query_count, dim, 10);
9090

91-
run_regression_test("Scalar", deglib::Metric::L2, 29000.0, 9.3, 0.94,
91+
run_regression_test("Scalar", deglib::Metric::L2, 29000.0, 9.3, 0.99,
9292
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
9393
deglib::distances::fp32_l2::L2Float{}, 100);
9494
}

0 commit comments

Comments
 (0)