Bug 1475

Summary: Test suite fails on ix86 due to unexpected rounding
Product: libsigrok Reporter: Stefan Brüns <stefan.bruens>
Component: PortabilityAssignee: Nobody <nobody>
Status: CONFIRMED ---    
Severity: normal    
Priority: Normal    
Version: unreleased development snapshot   
Target Milestone: ---   
Hardware: All   
OS: All   

Description Stefan Brüns 2020-01-01 15:44:27 CET
tests/strutil.c:99:F:sr_samplerate_string:test_mhz:0: Invalid result for '1.034567 MHz': 1.034566 MHz (1034566).

The failing code is:
test_samplerate(uint64_t samplerate);
test_samplerate(SR_MHZ(1.034567));

The error is caused by rounding of the "1.034567" float value. Depending on architecture and compiler flags, rounding is either up or down. The implicit cast to uint64_t truncates the value to the next smaller integer.

The result of this minimal test depends on the compiler flags, when using "-fexcess-precision=standard" (set by -std=c99) it rounds down, with "-fexcess-precision=fast" (e.g. set by -std=gnu99), it rounds up.

$> gcc-9 -Os -m32 -o round -fexcess-precision=standard round.c ;  ./round
---
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>

#define MHZ(x) ((x) * UINT64_C(1000000))

void t1(uint64_t x)
{
    printf("r: %" PRIu64 "\n", x);
}

void t2(float x)
{
    printf("r: %f\n", x);
}

int main(int argc, char** argv)
{
    if (argc < 2) {
        t1(MHZ(1.034567));               // 1034567 or 1034566
        t1(MHZ(1.03456700000000000001)); // 1034567 or 1034566
        t1(MHZ(1.0345670000000000001));  // 1034567
        t1(1034567.0);
        t2(MHZ(1.034567));
        t2(1034567.0);
    }
    return 0;
}
---
Comment 1 Stefan Brüns 2020-01-01 19:03:18 CET
Possible mitigations:

- use "test_samplerate(round(SR_MHZ(x))"
- change test_samplerate(uint64_t) to test_samplerate(double) and do the round inside test_samplerate.