C code sanity check
#1
would you guys test the following code for logic errors?
the goal here is to replace the current double to string conversion that's faulty in QB64
I must have concluded at least a dozen times that all was ok only to discover a bug
[edit1]
restricted the maximum digits to 15, with 16 digits there are too many cases that suffer from floating-point inaccuracies, like trying to print 1d-21 would give 9.999999999999999d-22
[edit2]
added a test program, let me know what you think
[edit3]
added another test
Code: (Select All)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>

#define QB64_MINGW

int str(double value){
    char buf[64];
    char buf2[64];
    int32_t i, j, lsd, exp;
    //double value=.000000000000000000001; //3.141592653589e3; //3.141592653589793e-10;
    #ifdef QB64_MINGW
        __mingw_sprintf((char*)&buf,"% .14Le",(long double) value);
    #else
        sprintf((char*)&buf,"% .14Le",(long double) value);
    #endif
    exp=atoi(&buf[18]);
    lsd=16;
    while((buf[lsd]=='0')&&(lsd>0)) lsd--;
    buf2[0]=buf[0]; // copy sign
    if(exp==0){
        for(i=1;i<=(lsd);i++){
            buf2[i]=buf[i];
        }
        if(buf2[lsd]=='.') // if no digits after . then nip it
            buf2[lsd]=0;   // by zero terminating
        else
            buf2[lsd+1]=0; // zero terminate
    }
    else if(exp<0){
        if((lsd-exp)>=19){ // use sci format
            for(i=1;i<=lsd;i++){
                buf2[i]=buf[i];
            }
            if(buf2[lsd]=='.'){
                buf2[lsd]='D';
                sprintf(&buf2[lsd+1],"%+03d", exp);
            }
            else{
                buf2[lsd+1]='D';
                sprintf(&buf2[lsd+2],"%+03d", exp);
            }
        }
        else{
            buf2[1]='.';
            for(i=2;i<=abs(exp);i++){
                buf2[i]='0';
            }
            buf2[abs(exp)+1]=buf[1]; // first non-zero digit
            j=3;                     // skip decimal point
            for(i=abs(exp)+2;i<(abs(exp)+lsd);i++){
                buf2[i]=buf[j];
                j++;
            }
            buf2[abs(exp)+lsd]=0; // zero terminate
        }
    }
    else if(exp>0){
        if((lsd<17)&&(exp<15)){
            buf2[1]=buf[1]; // first digit
            j=3;            // skip over .
            for(i=2;i<=(exp+1);i++){
                buf2[i]=buf[j];
                j++;
            }
            if((lsd>exp)&&(lsd>(j-1))){
                buf2[exp+2]='.';
                for(i=exp+3;i<=(lsd);i++){
                    buf2[i]=buf[j];
                    j++;
                }
                buf2[lsd+1]=0;
            }
            else{
                buf2[exp+2]=0;
            }
    }
    else{
        for(i=0;i<=lsd;i++){
            buf2[i]=buf[i];
        }
        if(buf2[lsd]=='.'){
            buf2[lsd]='D';
            sprintf(&buf2[lsd+1],"%+03d", exp);
        }
        else{
            buf2[lsd+1]='D';
            sprintf(&buf2[lsd+2],"%+03d", exp);
        }
    }
}
    printf("%s", buf2);
    return 0;
}

int main(void){
    time_t t;
    double x;
    char* ptr;
    char strx[50]="3141592653589793";
    char c;
    int i, j, k;
    srand((unsigned) time(&t));
    for(i=1;i<3;i++){
        for(j=1;j<15;j++){
            k=rand() %j;
            c=strx[k];
            strx[k]='.';
            x=strtod(strx,&ptr);
            str(x); printf("% .14e   %s\n",x,strx);
            strx[k]=c;
        }
    }
    printf("%s\n","====================================================");
    char stry[50]="3.141592653589793e";
    for(i=1;i<3;i++){
        for(j=1;j<15;j++){
            k=rand() %j;
            k=k * (13 - (-13)) + (-13);
            sprintf(&stry[18],"%d", k);
            x=strtod(stry,&ptr);
            str(x); printf("% .14e   %s\n",x,stry);
        }
    }
    printf("%s\n","====================================================");
    strx[0]='1';
    for(j=1;j<41;j++){
        for(i=1;i<=j;i++){
            strx[i]='0';
        }
        strx[i]=0;
        x=strtod(strx,&ptr);
        str(x); printf("% .14e   %s\n",x,strx);
    }
    printf("%s\n","====================================================");
    strx[0]='.';
    for(j=1;j<41;j++){
        for(i=1;i<=j;i++){
            strx[i]='0';
        }
        strx[i]='1';
        strx[i+1]=0;
        x=strtod(strx,&ptr);
        str(x); printf("% .14e   %s\n",x,strx);
    }
    return 0;
}
Reply
#2
I made some changes to the tests where I convert a string to double then convert that double to string using my version of str and convert that string to double and compare the two doubles, so far as I tested the results are ok
I did the same tests with a long double version and all is ok
Reply




Users browsing this thread: 1 Guest(s)