/* fpio-test.c

   K. Myneni, 21 Sep 2026  
   krishna.myneni@ccreweb.org
   Test compiler precision in converting decimal
   text of real numbers to IEEE double precision floating
   point (binary64).

   This is a port of the Forth floating point input tests.

   Build under gcc:
     gcc -o fpio-test fpio-test.c

   Build under dmc (Digital Mars C):
     sc.exe -c fpio-test.c
     optlink.exe fpio-test.obj

*/

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

bool cmp_idp_ref();

// global data
union dpdata
{
   int    i[2];
   double d;
};

// global data
union dpdata idp, ref;
int test_num, e_s1, e_s2, e_tot;
char section[4];

int main()
{
    e_tot = 0;
    strcpy(section, " I");
    e_s1 = 0;
    test_num = 1;
    printf("Section %s Testing Conversion of Exactly Representable Numbers\n",
       section);
    // I.1
    idp.d = 0.0e0; 
    ref.i[0] = 0; ref.i[1] = 0;
    cmp_idp_ref();
    // I.2
    idp.d = 9.99999935045640392457461415399766451285519391957298315801212e-39;
    ref.i[0] = 0x80000000; ref.i[1] = 0x380b38fb;
    cmp_idp_ref();
    // I.3
    idp.d = -1.00000001335143196001808973960578441619873046875e-10;
    ref.i[0] = 0xe0000000; ref.i[1] = 0xbddb7cdf;
    cmp_idp_ref();
    // I.4
    idp.d = 9.99999974737875163555145263671875e-05;
    ref.i[0] = 0xe0000000; ref.i[1] = 0x3f1a36e2;
    cmp_idp_ref();
    // I.5
    idp.d = 0.100000001490116119384765625e0;
    ref.i[0] = 0xa0000000; ref.i[1] = 0x3fb99999;
    cmp_idp_ref();
    // I.6
    idp.d = 1.0e0;
    ref.i[0] = 0; ref.i[1] = 0x3ff00000;
    cmp_idp_ref();
    // I.7
    idp.d = -1.0e0;
    ref.i[0] = 0; ref.i[1] = 0xbff00000;
    cmp_idp_ref();
    // I.8
    idp.d = 3.926990926265716552734375e-1;
    ref.i[0] = 0x60000000; ref.i[1] = 0x3fd921fb;
    cmp_idp_ref();
    // I.9
    idp.d = 5.235987901687622070312500e-1;
    ref.i[0] = 0x40000000; ref.i[1] = 0x3fe0c152;
    cmp_idp_ref();
    // I.10
    idp.d = 7.853981852531433105468750e-1;
    ref.i[0] = 0x60000000; ref.i[1] = 0x3fe921fb;
    cmp_idp_ref();
    // I.11
    idp.d = 1.047197580337524414062500e0;
    ref.i[0] = 0x40000000; ref.i[1] = 0x3ff0c152;
    cmp_idp_ref();
    // I.12
    idp.d = 1.178097248077392578125000e0;
    ref.i[0] = 0x80000000; ref.i[1] = 0x3ff2d97c;
    cmp_idp_ref();
    // I.13
    idp.d = 1.570796370506286621093750e0;
    ref.i[0] = 0x60000000; ref.i[1] = 0x3ff921fb;
    cmp_idp_ref();
    // I.14
    idp.d = 1.963495373725891113281250e0;
    ref.i[0] = 0x20000000; ref.i[1] = 0x3fff6a7a;
    cmp_idp_ref();
    // I.15
    idp.d = 2.094395160675048828125000e0;
    ref.i[0] = 0x40000000; ref.i[1] = 0x4000c152;
    cmp_idp_ref();
    // I.16
    idp.d = 2.356194496154785156250000e0;
    ref.i[0] = 0x80000000; ref.i[1] = 0x4002d97c;
    cmp_idp_ref();
    // I.17
    idp.d = 2.617993831634521484375000e0;
    ref.i[0] = 0xc0000000; ref.i[1] = 0x4004f1a6;
    cmp_idp_ref();
    // I.18
    idp.d = 2.748893499374389648437500e0;
    ref.i[0] = 0xe0000000; ref.i[1] = 0x4005fdbb;
    cmp_idp_ref();
    // I.19
    idp.d = 3.141592741012573242187500e0;
    ref.i[0] = 0x60000000; ref.i[1] = 0x400921fb;
    cmp_idp_ref();
    // I.20
    idp.d = 10.0e0;
    ref.i[0] = 0; ref.i[1] =0x40240000;
    cmp_idp_ref();
    // I.21
    idp.d = 1.0e1;
    cmp_idp_ref();
    // I.22
    idp.d = 0.10e2;
    cmp_idp_ref();
    // I.23
    idp.d = 0.010e3;
    cmp_idp_ref();
    // I.24
    idp.d = 0.0000010e7;
    cmp_idp_ref();
    // I.25
    idp.d = 0.000000000000010e15;
    cmp_idp_ref();
    // I.26
    idp.d = 0.0000000000000000000000000000000000010e37;
    cmp_idp_ref();
    // I.27
    idp.d = 1.0e10;
    ref.i[0] = 0x20000000; ref.i[1] = 0x4202a05f;
    cmp_idp_ref();
    // I.28
    idp.d = 9999999933815812510711506376257961984e0;
    ref.i[0] = 0x40000000; ref.i[1] = 0x479e17b8;
    cmp_idp_ref();
    e_s1 = e_tot;

    strcpy(section, "II");
    e_s2 = 0;
    test_num = 1; // Reset test number
    printf ("\nSection %s TESTING Rounding of Numbers\n", section);
    // II.1
    idp.d = 1.0e-10;
    ref.i[0] = 0xd9d7bdbb; ref.i[1] = 0x3ddb7cdf;
    cmp_idp_ref();
    // II.2
    idp.d = 2.71828182845904523536e0;
    ref.i[0] = 0x8b145769; ref.i[1] = 0x4005bf0a;
    cmp_idp_ref();
    // II.3
    idp.d = 3.14159265358979323846e0;
    ref.i[0] = 0x54442d18; ref.i[1] = 0x400921fb;
    cmp_idp_ref();
    // II.4
    idp.d = 3.518437208883201171875e+013;
    ref.i[0] = 0x00000002; ref.i[1] = 0x42c00000;
    cmp_idp_ref();
    // II.5
    idp.d = 1.00000005960464477550e0;
    ref.i[0] = 0x10000000; ref.i[1] = 0x3ff00000;
    cmp_idp_ref();
    // II.6
    idp.d = 5.00000000000000166533453693773481063544750213623046875e-1;
    ref.i[0] = 0x00000002; ref.i[1] = 0x3fe00000;
    cmp_idp_ref();
    // II.7
    idp.d = 62.5364939768271845828e0;
    ref.i[0] = 0xd5aa7ca4; ref.i[1] = 0x404f44ab;
    cmp_idp_ref();
    // II.8
    idp.d = 8.10109172351e-10;
    ref.i[0] = 0xaef0fd0c; ref.i[1] = 0x3e0bd5cb;
    cmp_idp_ref();
    // II.9
    idp.d = 9214843084008499e0;
    ref.i[0] = 0xec57761a; ref.i[1] = 0x43405e6c;
    cmp_idp_ref();
    // II.10
    idp.d = 1.50000000000000011102230246251565404236316680908203125e0;
    ref.i[0] = 0; ref.i[1] = 0x3ff80000;
    cmp_idp_ref();
    // II.11
    idp.d = 9007199254740991.4999999999999999999999999999999995e0;
    ref.i[0] = 0xffffffff; ref.i[1] = 0x433fffff;
    cmp_idp_ref();
    // II.12
    idp.d = 1.000000000000000111022302462515654042363166809082031250e+00;
    ref.i[0] = 0; ref.i[1] = 0x3ff00000;
    cmp_idp_ref();
    // II.13
    idp.d = 1.000000000000000111022302462515654042363166809082031251e+00;
    ref.i[0] = 1; ref.i[1] = 0x3ff00000;
    cmp_idp_ref();
    e_s2 = e_tot - e_s1;

    // Show test results

    printf("\nSection  I Error Count: %3d", e_s1);
    printf("\nSection II Error Count: %3d", e_s2);
    printf("\nTotal      Error Count: %3d\n", e_tot);
    return 0;
}


bool cmp_idp_ref()
{
    // output high 32, low 32 hex values
    bool p_f;

    p_f = !(idp.i[0] == ref.i[0]) && (idp.i[1] == ref.i[1]);
    if (p_f) {
        printf("\nERROR in test %s.%02d", section, test_num);
        printf("\nObtained   %08x  %08x",   idp.i[1], idp.i[0]);
        printf("\nShould be  %08x  %08x\n", ref.i[1], ref.i[0]);
        e_tot += 1;
    }
    test_num += 1 ;
    return(p_f);
}

