## Technote (troubleshooting)

## Problem(Abstract)

I'm using SPSS Statistics and have noticed that it sometimes doesn't produce correct results when rounding numbers using the RND function, and that in some cases the results differ across different versions or releases. Also, sometimes when I compute values in two different ways that are mathematically equivalent, I get slightly different results. Finally, I've noticed that if I type a number with more than 16 digits in it into a cell in the Data Editor, the value is sometimes changed by the program. Why are these things happening, and what can I do about them?

## Resolving the problem

All of these occurrences are functions of the fact that SPSS Statistics is working with finite precision and is therefore unable to exactly represent or perform error-free calculations on the infinitely large collection of numbers known as real numbers. Most of the time the discrepancies between true mathematical results and what the program produces will be very small and will go unnoticed. However, special care must be taken in situations where comparisons among values that are extremely close together are required or where very large and/or small numbers are involved.

The fundamental issue is that the collection of numbers designated by mathematicians as the field of real numbers contains an infinite or unlimited number of values, while the number of physical locations available for representation or storage of a number in a computer is finite or limited. The immediate implication of these facts is that not all real numbers can be represented or stored in a computer. More specifically: 1) For any specified real number, there is always another real number (actually, an infinite number of them) that is larger in magnitude (i.e., larger in absolute value), and 2) For any two specified real numbers, there are always an infinite number of real numbers in between those two numbers.

The numbers that can be stored or represented in a computer are thus a subset of the real numbers. This subset is limited in the range of numbers represented and in terms of precision. That is, some numbers are too large in magnitude to be represented in a computer, and within the range of numbers that can be represented, there is a limit to the precision with which numbers can be represented.

While there are some types of problems that can be handled via analytical methods that produce exact results via what is known as symbolic computations, many of the types of problems routinely handled by SPSS Statistics cannot be dealt with in this way. While extended precision methods such as quadruple precision (as opposed to the double precision methods generally used in SPSS Statistics) can make the errors smaller, they do not eliminate the problems and have costs in terms of memory and processing time. So-called arbitrary precision methods have prohibitive costs in terms of memory and processing time. None of these approaches represent a practical solution to these issues.

From the perspective of a user of the software, it is important to recognize that some small amounts of error are going to be involved in computations you perform with SPSS Statistics and similar programs. In the vast majority of situations you are unlikely to notice these errors and they are benign, with no practical effects on your results. The situations in which you generally need to be careful are those in which operations are performed that rely on equality comparisons, such as rounding and truncation.

Beginning with Version 17, SPSS Statistics offers the user the ability to set the number of bits by which a computed or entered value may fall short of equality to a rounding or truncation boundary and still be considered equal to that boundary minus some "fuzz" or error. This setting can be controlled via the FUZZBITS subcommand on the SET command or in the menus via Edit>Options and going to the bottom of the Data tab. The following Help text describes how this works and references some changes that have occurred over the years:

**Rounding and Truncation of Numeric Values****.** For the RND and TRUNC functions, this setting controls the default threshold for rounding up values that are very close to a rounding boundary. The setting is specified as a number of bits and is set to 6 at install time, which should be sufficient for most applications. Setting the number of bits to 0 produces the same results as in release 10. Setting the number of bits to 10 produces the same results as in releases 11 and 12.

• For the RND function, this setting specifies the number of least-significant bits by which the value to be rounded may fall short of the threshold for rounding up but still be rounded up. For example, when rounding a value between 1.0 and 2.0 to the nearest integer this setting specifies how much the value can fall short of 1.5 (the threshold for rounding up to 2.0) and still be rounded up to 2.0.

• For the TRUNC function, this setting specifies the number of least-significant bits by which the value to be truncated may fall short of the nearest rounding boundary and be rounded up before truncating. For example, when truncating a value between 1.0 and 2.0 to the nearest integer this setting specifies how much the value can fall short of 2.0 and be rounded up to 2.0.

__________

The RND and TRUNC functions were also altered to allow the user to control the number of bits of fuzz allowed on each individual invocation of the transformations. The following information appears in the Arithmetic Functions section of the Universals chapter of current versions of the SPSS Statistics Command Syntax Reference:

**RND.** RND(numexpr[,mult,fuzzbits]). Numeric. With a single argument, returns the integer nearest to that argument. Numbers ending in .5 exactly are rounded away from 0. For example, RND(-4.5) rounds to -5. The optional second argument, mult, specifies that the result is an integer multiple of this value—for example, RND(-4.57,0.1) = -4.6. The value must be numeric but cannot be 0. The default is 1.

The optional third argument, fuzzbits, is the number of least-significant bits by which the internal representation of numexpr (expressed as a 64-bit floating point binary) may fall short of the threshold for rounding up (e.g., 0.5 when rounding to an integer) but still be rounded up. For example, the sum 9.62 - 5.82 - 9.21 + 6.91 has an internal representation of 1.499999999999998 (on an Intel processor). With fuzzbits set to 0 and mult set to 1, this expression will round to 1.0, although the exact sum is 1.50 which would round to 2.0. Allowing the rounding threshold to have a small fuzziness compensates for the minute differences between calculations with floating point numbers and exact results. In this case, adding a fuzziness of 4 bits is sufficient to produce the expected result of 2.0.

If the argument fuzzbits is omitted, the value specified by SET FUZZBITS is used. The installed setting of FUZZBITS is 6, which should be sufficient for most applications. Setting fuzzbits to 0 produces the same results as in release 10. Setting fuzzbits to 10 produces the same results as in releases 11 and 12.

To produce the same results as in release 13, use the following expression in place of the RND function:

TRUNC(numexpr,1,0) + ((.5+TRUNC(numexpr,1,0)-numexpr)<max(1e-13,min(.5,numexpr*1e-13)))

To produce the same results as in releases 14, 15, and 16 use:

RND(numexpr,1,12.5-ln(max(1e-50,abs(numexpr)))/ln(2))

**TRUNC.** TRUNC(numexpr[,mult,fuzzbits]). Numeric. Returns the value of numexpr truncated toward 0. The optional second argument, mult, specifies that the result is an integer multiple of this value—for example, TRUNC(4.579,0.1) = 4.5. The value must be numeric but cannot be 0. The default is 1.

The optional third argument, fuzzbits, is the number of least-significant bits by which the internal representation of numexpr (expressed as a 64-bit floating point binary) may fall short of the nearest rounding boundary and be rounded up before truncating. For example, the sum 9.62 - 5.82 - 9.21 + 6.91 has an internal representation of 1.499999999999998 (on an Intel processor). With fuzzbits set to 0 and mult set to 0.1, this expression will truncate to 1.4, although the exact sum is 1.50 which would truncate to 1.5. Adding a small fuzziness to the nearest rounding boundary (in this case, 1.5) compensates for the minute differences between calculations with floating point numbers and exact results. In this case, adding a fuzziness of 5 bits is sufficient to produce the expected result of 1.5.

If the argument fuzzbits is omitted, the value specified by SET FUZZBITS is used. The installed setting of FUZZBITS is 6, which should be sufficient for most applications. Setting fuzzbits to 0 produces the same results as in release 10. Setting fuzzbits to 10 produces the same results as in releases 11 and 12.

To produce the same results as in release 13 use:

TRUNC(numexpr,1,0)+(TRUNC(numexpr,1,0)+1-numexpr <= 1e-13)

To produce the same results as in releases 14, 15, and 16 use:

TRUNC(numexpr,1,12.5-ln(max(1e-50,abs(numexpr)))/ln(2))

## Historical Number

66550