Consultor Eletrônico



Kbase P88093: Can subtraction of two decimal numbers having the same decimals precision have rounding problems?
Autor   Progress Software Corporation - Progress
Acesso   Público
Publicação   16/07/2004
Status: Unverified

GOAL:

Can subtraction of two decimal numbers having the same decimals precision have rounding problems?

GOAL:

If x, y are two decimal variables specified with a decimals 4 precision, can their difference, d = x - y; which is also a decimal variable specified to the same decimals 4 precision; ever suffer a loss of data due to ROUNDING?

FIX:

No, the Progress 4GL subtraction operation in does not have any rounding problems.

The following code empirically proves this by looping a million times, generating two random decimals in each iteration and confirming that their difference does not suffer any loss of data due to rounding:

DEFINE VARIABLE dx AS DECIMAL NO-UNDO DECIMALS 4 FORMAT "(9.9999)".
DEFINE VARIABLE dy AS DECIMAL NO-UNDO DECIMALS 4 FORMAT "(9.9999)".
DEFINE VARIABLE ix AS INTEGER NO-UNDO FORMAT "(99999)".
DEFINE VARIABLE iy AS INTEGER NO-UNDO FORMAT "(99999)".
DEFINE VARIABLE iIntegerDifference AS INTEGER NO-UNDO FORMAT "(99999)".
DEFINE VARIABLE dDecimalDifference AS DECIMAL NO-UNDO DECIMALS 4 FORMAT "(9.9999)".

DEFINE VARIABLE iCounter AS INTEGER NO-UNDO.

/* functions to generate random integers and cook decimals from these integers */
FUNCTION udfGeneratedRandomInteger RETURNS INTEGER FORWARD.
FUNCTION udfGeneratedDecimalFromInteger RETURNS DECIMAL (INPUT piVariable1 AS INTEGER) FORWARD.

/* functions to generate integer difference and decimal difference of the generated numbers*/
FUNCTION udfSubtractTheIntegers RETURNS INTEGER (INPUT piVariable1 AS INTEGER, INPUT piVariable2 AS INTEGER) FORWARD.
FUNCTION udfSubtractTheDecimals RETURNS DECIMAL (INPUT piVariable1 AS DECIMAL, INPUT piVariable2 AS DECIMAL) FORWARD.

/* loop a million times */
REPEAT iCounter = 1 TO 1000000:
ASSIGN
ix = udfGeneratedRandomInteger()
iy = udfGeneratedRandomInteger()
dx = udfGeneratedDecimalFromInteger(ix)
dy = udfGeneratedDecimalFromInteger(iy)
iIntegerDifference = udfSubtractTheIntegers(ix, iy)
dDecimalDifference = udfSubtractTheDecimals(dx, dy).
/*** If decimal difference is ROUNDED, then message the strings involved ***/
IF STRING(iIntegerDifference, "99999") <>
REPLACE(STRING(dDecimalDifference, "9.9999"),'.','') THEN
MESSAGE ix dx iy dy STRING(iIntegerDifference, "99999") REPLACE(STRING(dDecimalDifference, "9.9999"),'.','')
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END.

/* Generate a random integer */
FUNCTION udfGeneratedRandomInteger RETURNS INTEGER:
RETURN RANDOM(10000,99999).
END.

/* Cook a decimal from the generated integer */
FUNCTION udfGeneratedDecimalFromInteger RETURNS DECIMAL (INPUT piVariable AS INTEGER):
DEFINE VARIABLE c AS CHARACTER NO-UNDO.
c = STRING(piVariable).
SUBSTRING(c,1,1) = SUBSTRING(c,1,1) + '.'.
RETURN DECIMAL(c).
END.

/* Get the integer difference */
FUNCTION udfSubtractTheIntegers RETURNS INTEGER (INPUT piVariable1 AS INTEGER, INPUT piVariable2 AS INTEGER):
RETURN ABS(piVariable1 - piVariable2).
END.

/* Get the decimal difference */
FUNCTION udfSubtractTheDecimals RETURNS DECIMAL (INPUT piVariable1 AS DECIMAL, INPUT piVariable2 AS DECIMAL):
RETURN ABS(piVariable1 - piVariable2).
END.