Skip to content

Commit 8a7dea1

Browse files
committed
Convert bench.h to fixed-point math
- Use 64-bit integer microsecond timestamps - Use fixed-point math for formatting numbers Then, remove "except in benchmarks" exception from `README.md`.
1 parent 0c774d8 commit 8a7dea1

File tree

2 files changed

+62
-21
lines changed

2 files changed

+62
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Implementation details
2323
* Extensive testing infrastructure.
2424
* Structured to facilitate review and analysis.
2525
* Intended to be portable to any system with a C89 compiler and uint64_t support.
26-
* No use of floating types, except in benchmarks.
26+
* No use of floating types.
2727
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
2828
* Field operations
2929
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).

src/bench.h

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,82 @@
99

1010
#include <stdio.h>
1111
#include <string.h>
12-
#include <math.h>
1312
#include "sys/time.h"
1413

15-
static double gettimedouble(void) {
14+
static int64_t gettime_i64(void) {
1615
struct timeval tv;
1716
gettimeofday(&tv, NULL);
18-
return tv.tv_usec * 0.000001 + tv.tv_sec;
17+
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
1918
}
2019

21-
void print_number(double x) {
22-
double y = x;
23-
int c = 0;
24-
if (y < 0.0) {
25-
y = -y;
20+
#define FP_EXP (6)
21+
#define FP_MULT (1000000LL)
22+
23+
/* Format fixed point number. */
24+
void print_number(const int64_t x) {
25+
int64_t x_abs, y;
26+
int c, i, rounding;
27+
size_t ptr;
28+
char buffer[30];
29+
30+
if (x == INT64_MIN) {
31+
/* Prevent UB. */
32+
printf("ERR");
33+
return;
2634
}
27-
while (y > 0 && y < 100.0) {
28-
y *= 10.0;
35+
x_abs = x < 0 ? -x : x;
36+
37+
/* Determine how many decimals we want to show (more than FP_EXP makes no
38+
* sense). */
39+
y = x_abs;
40+
c = 0;
41+
while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
42+
y *= 10LL;
2943
c++;
3044
}
31-
printf("%.*f", c, x);
45+
46+
/* Round to 'c' decimals. */
47+
y = x_abs;
48+
rounding = 0;
49+
for (i = c; i < FP_EXP; ++i) {
50+
rounding = (y % 10) >= 5;
51+
y /= 10;
52+
}
53+
y += rounding;
54+
55+
/* Format and print the number. */
56+
ptr = sizeof(buffer) - 1;
57+
buffer[ptr] = 0;
58+
if (c != 0) {
59+
for (i = 0; i < c; ++i) {
60+
buffer[--ptr] = '0' + (y % 10);
61+
y /= 10;
62+
}
63+
buffer[--ptr] = '.';
64+
}
65+
do {
66+
buffer[--ptr] = '0' + (y % 10);
67+
y /= 10;
68+
} while (y != 0);
69+
if (x < 0) {
70+
buffer[--ptr] = '-';
71+
}
72+
printf("%s", &buffer[ptr]);
3273
}
3374

3475
void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
3576
int i;
36-
double min = HUGE_VAL;
37-
double sum = 0.0;
38-
double max = 0.0;
77+
int64_t min = INT64_MAX;
78+
int64_t sum = 0;
79+
int64_t max = 0;
3980
for (i = 0; i < count; i++) {
40-
double begin, total;
81+
int64_t begin, total;
4182
if (setup != NULL) {
4283
setup(data);
4384
}
44-
begin = gettimedouble();
85+
begin = gettime_i64();
4586
benchmark(data);
46-
total = gettimedouble() - begin;
87+
total = gettime_i64() - begin;
4788
if (teardown != NULL) {
4889
teardown(data);
4990
}
@@ -56,11 +97,11 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
5697
sum += total;
5798
}
5899
printf("%s: min ", name);
59-
print_number(min * 1000000.0 / iter);
100+
print_number(min * FP_MULT / iter);
60101
printf("us / avg ");
61-
print_number((sum / count) * 1000000.0 / iter);
102+
print_number(((sum * FP_MULT) / count) / iter);
62103
printf("us / max ");
63-
print_number(max * 1000000.0 / iter);
104+
print_number(max * FP_MULT / iter);
64105
printf("us\n");
65106
}
66107

0 commit comments

Comments
 (0)