Hello, my name is John McPherson, and I write C code for the U.S. Department of Labor. I am in the process of converting C code for a lot states from a 32-bit system to a 64-bit system. Some states have been converted, and most have gone smoothly, but one state is having a major problem. I have isolated the problem to one paticular module, and the code of this module follows:

``````#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#include "maff.h"
#include "maffdef"

int i,j,k;

int creg_(int kky,int kkq)
{
/* this s/r determines the regular tax rate for each emp.*/

int ky, kq, ky1, kq1;
int icla = 0;
int goto70 = 0;
double ra1;

ky = kky;
kq = kkq;
ky1 = ky-1;
kq1 = kq-1;

printf("\n%25s\n"," TAX RATE CALCULATION");
//printf("%7s %6s %8s %8s %8s %10s\n","WUNENG","J","RAP","KTAB","ICLA","CONRM");
/* printf(">>>>>>>>>>>>>>>>>>The value of knri is %d\n",  kri); */
if( kri-1<=0)
{
for(i=1;i<= ndis;i++) /*do 40 i=1, ndis*/
{
ra1 =  rap[i-1];
if(ra1>=0.)
{
icla = ra1/ xprap+10./ xnrap+2.;
if (ra1 > 15.)
icla = 10./( xnrap+15.)/( xprap+2.) ;
}
else
{
icla = (ra1+10.)/ xnrap+2.;
if(ra1<-10.)
icla = 1;
}
/* printf("The value of icla is %d TTTTTTTTTT\n",icla); */
conrm[i-1] =  xrate[icla-1][ ktab-1];
//aa[i-1] =  xrate[icla-1][0];
printf("KRI,KY,CONRM,ICLA,KTAB,XRATE are %d %d %lf %d %d %lf\n", kri,ky,conrm[i-1],icla,ktab,xrate[icla-1][ktab-1]);
}
}
else /* kri-1 > 0 */
{
/* (variable rap intervals,  kri=2) */
for(j=1;j<= ndis;j++)
{
conrm[j-1] = 0.0;
ra1 =  rap[j-1];
ra1 = ra1/100.0;
for(i=1;i<= knri;i++)
{
if(ra1<0.0)
{
if(ra1 <= xrapi[i-1] + 0.0000001)
{
goto70 = 1;
printf("DEBUG: ra1 is %lf, xrapi is %lf\n", ra1, xrapi[i-1]);
break;
}
}
else
{
if(ra1 <  xrapi[i-1])
{
goto70 = 1;
printf("DEBUG: ra1 is %lf, xrapi is %lf\n", ra1, xrapi[i-1]);
break;
}
}
}

if(!goto70)
{
i =  knri+1;
printf("DEBUG: ra1 is %lf, xrapi is %lf, i is %d\n", ra1, xrapi[i-1], i);
}

icla = i;
goto70 = 0;

conrm[j-1] = xrate[icla-1][ktab-1];

/* printf("%7s %6d %10.4f %6d %6d %10.5f\n","WUNENG1", j,rap[j-1],ktab,icla,conrm[j-1]); */

conswm[j-1] = xtrigs[icla-1];
printf("KRI,KY,CONRM,ICLA,KTAB,XRATE are %d %d %lf %d %d %lf\n", kri,ky,conrm[i-1],icla,ktab,xrate[icla-1][ktab-1]);

}

}

return 0;
}``````

This code works for the first two years the module is called( this application pedicts the unemploymnet trust fund for the state in future years), but starting in the third year it is called, the 32-bit and 64-bit systems start getting different results. Below is the Debug listing for the 64-bit code in the third year:

``````TAX RATE CALCULATION
DEBUG: ra1 is 0.447402, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.364693, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.307749, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.276921, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.254421, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.239018, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.227467, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.218050, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.207246, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.204366, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.202762, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.197982, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.182876, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.186260, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.177461, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.184956, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.176551, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.167812, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 44 6 1.220000
DEBUG: ra1 is 0.168844, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 44 6 1.220000
DEBUG: ra1 is 0.173439, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.173427, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.174459, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.172511, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 45 6 1.070000
DEBUG: ra1 is 0.169946, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 44 6 1.220000
DEBUG: ra1 is 0.165021, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.830000 44 6 1.220000``````

This is only a partial debug listing, but it is enough to complare to the 32-bit debug listing below:

``````TAX RATE CALCULATION
DEBUG: ra1 is 0.449120, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.359665, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.300799, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.260753, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.227522, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.228402, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.214150, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.211497, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.196708, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.195283, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.183477, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.181437, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.181227, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.174001, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.178600, xrapi is 0.000000, i is 45
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 45 6 1.070000
DEBUG: ra1 is 0.119736, xrapi is 0.120000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.940000 37 6 2.450000
DEBUG: ra1 is 0.156955, xrapi is 0.160000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 43 6 1.380000
DEBUG: ra1 is 0.166056, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.940000 44 6 1.220000
DEBUG: ra1 is 0.167515, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.940000 44 6 1.220000
DEBUG: ra1 is 0.163263, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.940000 44 6 1.220000
DEBUG: ra1 is 0.163469, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.940000 44 6 1.220000
DEBUG: ra1 is 0.160229, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.940000 44 6 1.220000
DEBUG: ra1 is 0.159966, xrapi is 0.160000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 1.040000 43 6 1.380000
DEBUG: ra1 is 0.160318, xrapi is 0.170000
KRI,KY,CONRM,ICLA,KTAB,XRATE are 2 4 0.940000 44 6 1.220000``````

The first issue is that on both the 32-bit and 64-bit systems, the simple assign of xrate to conrm does not seem to work, and it is a simple assignment statement. The code still seems to work on both systems, but they start producing different values, and with the assign statement acting strange on both, I don't know which to trust. I have reorganized memory on the 64-bit system, by reordering variable in the .h files, but it does not change anything. I solved a problem in another state by reorganizing memory, so that was one of my early attempts with this state. Note that all variables in this module are accounted for by .h declarations if they are not declared in this module, and the code compiles cleanly on both the 32-bit and 64-bit systems. Any help with this is greatly appreciated, and this is very strange problem.

All 11 Replies

I can't say anything useful without knowing the declared types of the variables in the missing include files. The variable names are terse and cryptic (ky, kky, etc.) and the code contains no useful comments. I strongly suspect (based on many years of working with them) that the code was written by engineers.

commented: Engineers tend to make bridges that bare stand up. +14

When I have to track this problem done I focus on one resulting value at a time. So take the result, just one and add printf's as needed to see what the values are going along and then the result. I see a lot more data than would be required. That is, one failure is enough. Fix the one failure then the next.

Yes, I do need to give a description of all these variables. The description is:

``````   The variables in the creg module

kky, ky - This variable is the year being calculated. The kky variable is passed in, varies from one to twelve, and ky is equated
to it and used in the module. Year one and two are existing bas data, years three through twelve are the ten projection years.

kkq,kq  - This variable is the for the four quarters of the year. kkq is passed in, and kq is equated to it and used in the module.
The creg module is caled once a year in the code, so the valuee of kkq will be two, since this state's fiscal year ends
on June 30th.

rap,ra1 - This variable indicates a percentage assigned to a group of employers in the distribution. All the employers in a state
are grouped into a distribution, usually around 280 records. The reserve ratio percentage, rap, is part of that record,
and indicates how the group of employers rate in how many employees they lay off. This variable ranges from negative
to positive.

ndis    - This variable is the number of records in the distribution described just above. it is usually around 280 records.

xrapi   - This variable is an array of intervals compared to the rap(ra1), effectively acting as a delimeter to determine which range
of tax rates apply.

xprap,xnrap - These two variables are the size of the postive rap intervals, and the size of the negative rap intervals.

knri    - This variable is the number of tax rates intervals per schedule, which will be one less than the number of tax rates.
This state has 44 intervals, and thus 45 tax rates per schedule.

ktab    - The index to which unemployment rate tax schedule applies this year. This state has seven schedule, where the first
schedule(subscript 0) is the lowest taxes, and the seventh is the highest. The schedule to be applied will depend
on the current amount in the state unemployment trust fund.

kri     - Indicates whether the rap intervals are constant or variable. This uses variable rap intervals.

icla    - This is an internal vaiable to determine the subscript for the tasx rate. See next description for more details.

xrate   - This is the two-dimensional tax rate array. The first subscript is the tax rate within this schedule, and the second
subscript is the tax schedule that applies this year. In this module, the icla variable is calculated to determine
which tax rate appliles to each record of the distribution, and ktab is passed in to indicate the schedule used this year.

goto70  - This variable name is a bad leftover of when this application was written in Fortran( I inherited this code,
I've learned to live with these quirks). Basically, it indicates whether or not the proper rap interval was found before
the code checked all of the the rap intervals. If not, icla is set to the total number of tax rates.

conrm   - This variable is the array of tax rates that will be used in the calculation of the contributions for the next year.
Since creg is called once per year, this array of rates will apply all four quarters of the upcoming year. The creg
module is called in the second quarter of the year(say 2018) and the conrm rates will apply the following year(2019).
The conrm array size is the number of distribution records, one rate per record.

conswm  - This is special tax rate calculated in addition to the regular(conrm) tax rate. This is working correctly, so don't

I hope this helps clarify the module.

include <stdint.h>

void *p = 0xc8f68000;
uint64_t v = (uintptr_t)p;

Where is `rap[ ]` assigned a value? You should look there because the value of `ra1`comes from `rap[ ]`, so if the values in `ra1`differ it's that `rap[ ]`values are already coming different from some other code, not the one you show.

Another possibility is to assure the operation in line 59: `ra1 = ra1/100.0;` maybe double precision in 32 and 64 bit machines do not match the same.

The distribution I mentioned in several variable descriptions is a file that is read into the application in a separate read module. The rap array is declared in a .h file, so the value is seen by all modules in the application. I have verified that the rap value is not changing elsewhere in the application.

Is it possible for you to change lines 58 and 59 from:

``````ra1 =  rap[j-1];
ra1 = ra1/100.0;``````

to:

``````ra1 =  rap[j-1];
printf("DEBUG: ra1 is %lf\n", ra1);
ra1 = ra1/100.0;
printf("DEBUG: ra1 is %lf\n", ra1);``````

and debug again?

I am in the process of converting C code for a lot states from a 32-bit system to a 64-bit system

I don't see a single line in there that would work in 32 bit C and not work in 64 bit C. I question whether you've truly isolated the problem code and whether it worked in 32 bit C.

The first issue is that on both the 32-bit and 64-bit systems, the simple assign of xrate to conrm does not seem to work, and it is a simple assignment statement.

You yourself say here that it does not work in 32 bit.

The code still seems to work on both systems, but they start producing different values

If it worked on both systems, they would produce the same values, yes?

and with the assign statement acting strange on both, I don't know which to trust.

OK, it is not working on the 32 bit system. So trust neither.

Garbage in, garbage out. If you're porting from System A to System B, you can't have any confidence that B will work if you don't have confidence that A worked in the first place. In this case A is 32 bits, B is 64 bits.

Thus I would suggest that looking at the 32 bit vs 64 bit debug printouts and figuring out where they diverge is largely a waste of time.

Or perhaps not. If the error is in fact roundoff or overflow error, you note that the first two years agree with each other, then they diverge. Everything else being equal, I'd expect the 32 bit system to hit that roundoff/overflow earlier than the 64 bit system, so if I HAD to trust one of them, I'd go with trusting the 64 bit system debug readouts. If you can note an ESCALATING discrepancy between the two debug printouts as time goes on, that might shove my thinking towards the roundoff/overflow error, possibly due to different lengths in the types.

You are fortunate that you were given this porting project, because it seems to have revealed a bug in the original 32 bit code that likely would have remained undetected if not for the porting project. I'd step through the logic and try to catch any logic error, which you likely have done. THEN I would play around with the types on both systems and run it. Change floats to doubles and vice-versa. See if you notice a difference. If you do, you're likely looking at round-off or overflow error. Then change the integral types. `stdint.h` has been mentioned. Use it. Change the `int` and `long` types to some exact length like `int32_t`. See if it makes a difference. If you can run it on a Big Endian vs. Little Endian machine, give that a whirl. Experiment with the compiler flags, compilers, etcetera, etcetera.

If the code is solid, it should give the same results no matter what you throw at it, or results so close to be negligible. From your writeup, I expect there is a bug in the code itself that has absolutely nothing to do with 32 bit vs. 64 bit porting problems.

commented: It would be interesting to see what the compiler says when all errors are turned on. gcc -Wall +14

From a purely non-technical point it seems to me that the problem is you don't know what constitutes "correct" output.

The first issue is that on both the 32-bit and 64-bit systems, the simple assign of xrate to conrm does not seem to work, and it is a simple assignment statement.

This confirms that there is a bug in the original code. Do you have a set of test values for which you know the correct output values? If not, then the best you can hope for is to produce a 64 bit version that replicates the original bug.

commented: Time to challenge beliefs and assumptions. +14

I was able to find the error inthe code I posted. so that problem is solved. Thanks to everyone for their help.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, learning, and sharing knowledge.