0

Hello, this is John McPherson, writing code for the U.S. Department of Labor. I am working on developing a new Benefit Finanacila Model for the state of Oregon, and I am having a problem with the printing of large numbers that are converted to strings. It works most of the time, but occasionally the least significant digits are dropped. Below is a sample fo the bad output:

                                                                             COMBINED QUARTERLY OUTPUT

                   INSED        TOTAL           TAXABLE       CONTRIBUTIONS     BENEFITS          ENDING TF           INTEREST
                   UNEMP        WAGES            WAGES                                             BALANCE
                   RATE         (000)            (000)

2016-1    2.56       16,334,284      14,112,227     149,661,400     133,579,377      2,813,499,313        15,770,753
2016-2    1.95       17,010,421      11,302,061     227,955,435     111,617,704       2,945,720,62        15,883,018
2016-3    1.81       17,612,342       8,574,811     182,562,698     111,926,233      3,032,740,405        16,383,879
2016-4    2.18       17,550,112       6,096,369      98,110,759     147,675,516      2,999,866,967        16,690,319
YEAR      2.12       68,507,158      40,085,467     658,290,291     504,798,829      2,947,956,437(*)     64,727,968

2017-1    2.62       17,483,115      15,138,635      69,753,069     175,310,418      2,911,141,623        16,832,005
2017-2    1.92       17,821,771      11,899,153     213,966,039     139,309,254      3,002,107,495        16,310,086
2017-3    1.88       18,491,240       9,118,938     168,179,934     145,372,024      3,041,606,196        16,690,792
2017-4    2.28       18,526,562       6,556,129     128,885,005     165,550,977        3,021,694,4        16,753,779
YEAR      2.20       72,322,689      42,712,855     580,784,048     625,542,673       2,994,137,79(*)     66,586,662

2018-1    2.68       18,418,529      15,912,885      92,662,843     185,601,074      2,945,711,250        16,955,478
2018-2    1.95       18,778,872      12,468,208     224,895,815     147,099,767      3,040,011,790        16,503,492
2018-3    1.91       19,484,389       9,580,614     176,212,409     154,539,794      3,078,597,377        16,913,971
2018-4    2.27       19,521,788       6,914,897     142,310,499     175,422,480      3,062,446,901        16,960,505
YEAR      2.20       76,203,578      44,876,604     636,081,567     662,663,115      3,031,691,330(*)     67,333,446

2019-1    2.68       19,597,131      16,829,156     102,713,923     196,159,738      2,986,205,220        17,205,135
2019-2    1.95       19,980,532      13,091,251     243,513,646     156,556,595      3,089,902,993        16,739,721
2019-3    1.91       20,731,195      10,074,340     189,427,103     164,982,193      3,131,520,561        17,172,658
2019-4    2.27       20,770,987       7,292,516     145,773,161     187,583,368      3,106,939,826        17,229,472
YEAR      2.20       81,079,845      47,287,263     681,427,832     705,281,893      3,078,641,400(*)     68,346,986

2020-1    2.68       20,851,151      17,795,477     105,520,869     207,216,115      3,022,705,919        17,461,339
2020-2    1.95       21,259,086      13,734,832     257,496,067     166,724,995      3,130,417,812        16,940,821
2020-3    1.91       22,057,784      10,587,669     198,739,558     178,950,769      3,167,586,897        17,380,296
2020-4    2.27       22,100,122       7,687,500     153,200,902     201,992,414      3,136,201,694        17,406,308
YEAR      2.20       86,268,144      49,805,478     714,957,396     754,884,293       3,114,227,81(*)     69,188,764

2021-1    2.68       22,165,164      18,839,685     111,236,188     219,294,815      3,045,775,989        17,632,922
2021-2    1.94       22,598,459      14,444,376     272,605,501     178,240,003      3,157,206,445        17,065,957
2021-3    1.90       23,447,766      11,184,607     209,006,486     193,386,069      3,190,366,731        17,538,869
2021-4    2.29       23,488,121       8,166,195     170,944,138     218,821,708      3,160,012,395        17,524,234
YEAR      2.20       91,699,510      52,634,863     763,792,313     809,742,595      3,138,340,890(*)     69,761,983

2022-1    2.73       23,547,239      19,936,997     124,811,106     237,504,809      3,065,097,578        17,777,886
2022-2    2.01       24,006,027      15,180,352     295,196,840     197,239,757      3,180,218,308        17,164,647
2022-3    1.95       24,911,015      11,817,728     224,767,649     215,349,006      3,207,254,136        17,617,186
2022-4    2.32       24,958,919       8,684,426     174,979,008     239,246,188      3,160,559,932        17,571,976
YEAR      2.25       97,423,200      55,619,503     819,754,603     889,339,761      3,153,282,989(*)     70,131,695

2023-1    2.74       25,027,430      21,100,837     128,585,820     235,122,339       3,071,858,23        17,835,609
2023-2    2.00       25,518,124      15,947,075     312,429,219     196,599,018      3,204,924,997        17,235,774
2023-3    1.95       26,480,192      12,482,573     236,120,121     217,032,816      3,241,830,452        17,819,150
2023-4    2.32       26,531,264       9,233,862     199,704,880     239,352,256      3,220,001,883        17,817,807
YEAR      2.25      103,557,010      58,764,347     876,840,040     888,106,429      3,184,653,339(*)     70,708,339

2024-1    2.74       26,603,157      22,327,157     147,729,743     249,214,723      3,136,736,131        18,220,229
2024-2    2.00       27,124,745      16,733,208     345,618,020     210,964,524      3,289,011,902        17,621,273
2024-3    1.95       28,147,385      13,173,036     259,025,286     235,895,942      3,330,387,333        18,247,088
2024-4    2.32       28,201,672       9,809,342     203,914,839     258,075,629      3,294,497,337        18,270,794
YEAR      2.25      110,076,959      62,042,742     956,287,888     954,150,818      3,262,658,926(*)     72,359,385

The column that is incorrect on occasion is the Ending TF Balance. All of the values in that colmn should be 2 billion somthing or 3 billion something, but you can see that some of the values are less than that, since the ones digit, or both the ten and ones digit, have been dropped. The code that does the printing is the following:

void print_table1A(int kkyear,int iyear1,int kkq,int kktt)
{
      for(i=1; i<12; i++)
      {
                for(j=0;j<4;j++)
                {
                        if(j==0)
                                jw_tca[i]+=tcon[j][i];
                        if(j==1)
                                jw_tca[i]+=tcon[j][i];
                        if(j==2)
                                jw_tca[i]+=tcon[j][i];
                        if(j==3)
                                jw_tca[i]+=tcon[j][i-1];
                        printf("\n@@@@ ky,kq,tcon, are %d %d %.4f\n", i,j,tcon[j][i]);
                }
                printf("\n@@@@ ky,kq,jw_tca are %d %d %.4f\n", i,j, jw_tca[i]);
        }

    /**************************************************/
    /*                Print TABLE 1A                  */
    /**************************************************/

        char *hd1[] = {"      ","   INSED","     TOTAL","          TAXABLE","       CONTRIBUTIONS","  BENEFITS","          ENDING TF","          INTEREST"};
        char *hd2[] = {"      ","   UNEMP","     WAGES","          WAGES"," "," ","                                        BALANCE"," "};
        char *table1A[] = {"- TABLE 1A -", "COMBINED QUARTERLY OUTPUT", "    (000)", "   RATE", "(*) FOUR QUARTER AVERAGE TF BALANCE"};

       // yx=2004;
        //yx=2005;

        fprintf(ff61, "\n%64s", table1A[0]);
        fprintf(ff61, "\n\n%70s", table1A[1]);
        fprintf(ff61, "\n\n%s %s %s %s %s %s %s %s\n", hd1[0], hd1[1], hd1[2], hd1[3], hd1[4], hd1[5], hd1[6], hd1[7]);
        fprintf(ff61, "%s %s %s %s %s %s %s %s\n", hd2[0], hd2[1], hd2[2], hd2[3], hd2[4], hd2[5], hd2[6], hd2[7]);
        fprintf(ff61, "%14s %11s %15s \n\n", table1A[3], table1A[2], table1A[2]);

        for(ix=3;ix<=12;ix++)
        {
          i_yr[ix-1] =kfpy1+1898+ix-1;
          if (kfpy1<80)
            i_yr[ix-1]+= 100;

                tintfa = 0.0;
                fundt_av = 0.0;

                for(jx=1;jx<=4;jx++)
                {
                        tintfa+= tintf[jx-1][ix-1];
                        fundt_av+= fundt[jx-1][ix-1][1];
                        if(jx > 1)
                        {
                          fprintf(ff61, "%d-%d\t%6.2f\t%15s\t%15s\t%15s\t%15s\t%18s\t%12s\n", i_yr[ix-1], jx, 100*(qiq[jx-1][ix-1]), cst(pay[jx-1][ix-1][1]),
 cst(jw_pay[jx-1][ix-1]), cst(tcon[jx-2][ix-1]), cst(tben[jx-1][ix-1]), cst(fundt[jx-1][ix-1][1]), cst(tintf[jx-1][ix-1]));
                        }
                        else
                        {
                          fprintf(ff61, "%d-%d\t%6.2f\t%15s\t%15s\t%15s\t%15s\t%18s\t%12s\n", i_yr[ix-1], jx, 100*(qiq[jx-1][ix-1]), cst(pay[jx-1][ix-1][1]),
 cst(jw_pay[jx-1][ix-1]), cst(tcon[3][ix-2]), cst(tben[jx-1][ix-1]), cst(fundt[jx-1][ix-1][1]), cst(tintf[jx-1][ix-1]));
                        }
                }
                fprintf(ff61, "%s\t%6.2f\t%15s\t%15s\t%15s\t%15s\t%18s%s\t%12s\n", "YEAR", 100*(qia[ix-1]), cst(payc[ix-1][1]/E3), cst(payc[ix-1][0]/E3), cst
(jw_tca[ix-1]), cst(tbena[ix-1][0]), cst(fundt_av/4), "(*)" ,cst(tintfa));
                fprintf(ff61, "\n");
        }
        fprintf(ff61, "\n\n%s\n\n", table1A[4]);

}

This code is used by multiple states, and works for those states. I have checked the output for Virginia, which uses this code and has values over a billion, and the printout works fine for them. The routine to get these large numbers converted to strings with commas in them is cst call you see in the fprintf statements above. The cst code follows:

char *cst(double wukong)
{
        int len, dash, i, j, k;
        int whole, remain;
        char *str, *str1, *sremain;
        char comma[1] = ",";
        int frac, rem;
        int ind=0,commain=0,nega=0;

        str = malloc(1000);
        str1 = malloc(1000);
        sremain = malloc(1000);

        if(wukong<0.0)
        {
           wukong = - wukong;
           nega = 1;
        }

        if(wukong > 2147483646.9)
        {
          frac = (int)(wukong - (int)(wukong/1000.)*1000.0);
          sprintf(sremain, "%s%d",",",frac);
          wukong = wukong/1000.;
          ind = 1;
        }

        if(wukong-(int)wukong<0.500)
          whole = (int)wukong;
        else
          whole = (int)wukong + 1;

        do
        {
           rem = whole%1000;
           whole = whole/1000;
           if(commain)
           {
             if(whole>0)
             {
               if(rem>99)
                 sprintf(str, "%d%s%s", rem,",",str1);
               else if((rem>9)&&(rem<100))
                 sprintf(str, "%d%d%s%s",0,rem,",",str1);
               else if((rem>0)&&(rem<10))
                 sprintf(str, "%s%d%s%s","00",rem,",",str1);
               else
                 sprintf(str, "%s%s%s", "000",",",str1);
             }
             else
               sprintf(str, "%d%s%s", rem,",",str1);
           }
           else
           {
             if(whole>0)
             {
               if(rem>99)
                 sprintf(str, "%d", rem);
               else if((rem>9)&&(rem<100))
                 sprintf(str, "%d%d",0,rem);
               else if((rem>0)&&(rem<10))
                 sprintf(str, "%s%d","00",rem);
               else
                 sprintf(str, "%s", "000");
             }
             else
               sprintf(str, "%d", rem);
           }
           strcpy(str1,str);
           commain++;
        }while(whole>0);

        if(nega)
           sprintf(str,"%s%s","-",str1);

        free(str1);

        if(ind)
          return strcat(str,sremain);
          /* return strcat(str,",000");*/
        else
          return str;

}

This code is used by all of the states with Benefit Financial Models, and it works in all of them. As you can see in the output, it also works for Oregon most of the time, but the occasional drroped digit has to be resolved. Any help you give me for this problem is greatly appreciated.

3
Contributors
4
Replies
43
Views
6 Months
Discussion Span
Last Post by AssertNull
1

I don't know what IDE you use but I'd examine the cst() function in depth. I fear there's a few chances that the integers in there are not the right choice. Maybe you should try a ready to use function for float to string?
https://www.google.com/search?q=float+to+string finds this has priors to read over.

Edited by rproffitt: Grammar.

Votes + Comments
kudos!
0

SInce the cst function works for everyother state( and other double printed for Oregon), I am leery of trying to do any changes within that function. I hunted around Google and found simple C routine to convert doubles to strings with commas, and it works fine for the TF field that has a problem in the Oregon printout. I just used it for that field for the time being, and if the cst routine has problems in the future, I will substitute thsi new routine.

0

I wonder if the fact you are coding for Oregon that the numbers are lower in value than for Oregon. Remember I don't know your IDE, compiler and more so all I can do is read the cst() function code and see what could be an issue with overflowing a data type.

Again, I can't know what you have for the compiler, IDE, settings and such but that function does look breakable.

1

As a general comment, you've had many threads dealing with buffer overflows, NULL pointers, spacing issues, conversion issues, etc., etc. that would appear to be less problematic is you used C++ rather than C.

I'm not a purist, so I'm all for leaving stuff in C and not fixing what ain't broken as opposed to going all object-oriented with this stuff. That said, all the stuff that goes wrong using C-style strings, in particular the printf and scanf stuff, as well as the NULL terminator and malloc/free stuff, all that goes away using C++ style strings. In addition, a lot of your array isssues and array resizing issues go away when you use vectors and the like. And it's all compatible with C. In addition there is the awesome >> and << operators available in C++ that solve the problem of sometimes having eight spaces instead of six between columns, or a tab, that's been crashing your program.

There's also a wonderful library called iomanip that really helps with columns. Finally, as far as conversions go, there is a wonderful tool called stringstreams in C++ that converts doubles to ints, ints to strings, whatever you want.

I think it would be well worth the learning curve for you to convert at least some of this to C++ and take advantage of some of its capabilities. Again, you can do it piecemeal (learn what you want, as you need it, and you can ignore all the classes and templates and STL, etc., etc.).

Food for thought. Nothing wrong with C, but consider using some of C++ that makes a lot of this stuff easier and still lets you mostly use C. It seems particularly useful for some parts of your ongoing project.

Votes + Comments
My other story. Write an enterprise class app in C#. No pointers allowed. It's been out there for a decade now.
This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.