Previous Page Next Page Contents

DIGITS -- the significant digits of floating point numbers

Introduction

The environment variable DIGITS determines the number of significant decimal digits in floating point numbers. The default value is DIGITS = 10.

Call(s)


DIGITS
DIGITS := n

Parameters

n - a positive integer smaller than 2^31.

Related Functions

float, Pref::floatFormat, Pref::trailingZeroes

Details

Example 1

We convert some exact numbers and numerical expressions to floating point approximations:

>> DIGITS := 10: 
   float(PI), float(1/7), float(sqrt(2) + exp(3)), float(exp(-20))
       3.141592654, 0.1428571429, 21.49975049, 0.000000002061153622
>> DIGITS := 20:
   float(PI), float(1/7), float(sqrt(2) + exp(3)), float(exp(-20))
      3.1415926535897932385, 0.14285714285714285714,
      
         21.49975048556076279, 0.000000002061153622438557828
>> delete DIGITS:

Example 2

We illustrate error propagation in numerical computations. The following rational number approximates exp(2) to 17 decimal digits:

>> r := 738905609893065023/100000000000000000:

The following float call converts exp(2) and r to floating point approximations. The approximation errors propagate and are amplified in the following numerical expression:

>> DIGITS := 10: float(10^20*(r - exp(2)))
                                   320.0

None of the digits in this result is correct. A better result is obtained by increasing DIGITS:

>> DIGITS := 20: float(10^20*(r - exp(2)))
                           276.95725394785404205
>> delete r, DIGITS:

Example 3

In the following, only 10 of the entered 30 digits are regarded as significant. The extra digits are stored internally, anyway:

>> DIGITS := 10:
   a := 1.23456789666666666666666666666;
   b := 1.23456789444444444444444444444
                                1.234567897
      
                                1.234567895

We increase DIGITS. Because the internal representation of a and b is correct to 30 decimal place, the difference can be computed correctly to 20 decimal places:

>> DIGITS := 30: a - b
                      0.00000000222222222222222222222
>> delete a, b, DIGITS:

Example 4

We compute a floating point number with a precision of 10 digits. Internally, this number is stored with about 9 guard digits to 19 correct digits. Increasing DIGITS to 30, the correct guard digits become visible. The remaining 11 decimal digits are created by padding the internal representation with binary zeroes. In the output, the internal representation is converted into a decimal representation. This converts the trailing binary zeroes to 11 nontrivial decimal digits. With the the call Pref::trailingZeroes(TRUE), trailing zeroes of the decimal representation become visible:

>> DIGITS := 10: a := float(1/9)
                               0.1111111111
>> Pref::trailingZeroes(TRUE): DIGITS := 30: a
                     0.111111111111111111109605274000
>> Pref::trailingZeroes(FALSE): delete a, DIGITS:

Example 5

For the float evaluation of the sine function, the argument is reduced to the standard interval [0, 2*PI]. For this reduction, the argument must be known to some digits after the decimal point. For small DIGITS, the digits after the decimal point are pure round-off if the argument is a large floating point number:

>> DIGITS := 10: sin(float(2*10^20))
                               0.9576594803

Increasing DIGITS to 50, the argument of the the sine function has about 30 correct digits after the decimal point. The first 30 digits of the following result are reliable:

>> DIGITS := 50: sin(float(2*10^20))
           -0.9859057707420871849896773829691365946134713391129

For very large floating point arguments, MuPAD's trigonometric functions produce errors if DIGITS is not large enough:

>> DIGITS := 10: sin(float(2*10^30))
      Error: Loss of precision;
      during evaluation of 'sin'
>> DIGITS := 50: sin(float(2*10^30))
           0.17950046751493908795061771243112520647287791588203
>> delete DIGITS:

Example 6

At least one digit after the decimal point is always displayed. In the following example, the number 3.9 is displayed as 3.0 to indicate that the digit 9 after the decimal point is not significant:

>> DIGITS := 1: float(PI), 3.9, -3.2
                              3.0, 3.0, -3.0
>> delete DIGITS:

Example 7

We compute float(10^40*8/9) with various values of DIGITS. Rounding takes into account all guard digits, i.e., the resulting integer makes all guard digits visible:

>> for DIGITS in [9, 10, 11, 19, 20, 21, 28, 29, 30] do
       print("DIGITS" = DIGITS, round(float(10^40*8/9)))
   end_for:
          "DIGITS" = 9, 8888888887243627086483687557525021917184
      
          "DIGITS" = 10, 8888888888888888888303079319556646240256
      
          "DIGITS" = 11, 8888888888888888888303079319556646240256
      
          "DIGITS" = 19, 8888888888888888888303079319556646240256
      
          "DIGITS" = 20, 8888888888888888888888888888827804909568
      
          "DIGITS" = 21, 8888888888888888888888888888827804909568
      
          "DIGITS" = 28, 8888888888888888888888888888827804909568
      
          "DIGITS" = 29, 8888888888888888888888888888888888888864
      
          "DIGITS" = 30, 8888888888888888888888888888888888888864

The results show that the internal representation coincides for values of DIGITS between 10 and 19. Increasing DIGITS to 20 leads to an extended internal representation which is constant through DIGITS = 28. From DIGITS = 29 on, a yet more extended internal representation is used etc.

Example 8

The following procedure allows to compute numerical approximations with a specified precision without changing DIGITS as a global variable. Internally, DIGITS is set to the desired precision and the float approximation is computed. Because of save DIGITS, the value of DIGITS is not changed outside the procedure:

>> Float := proc(x, digits) 
            save DIGITS;
            begin
              DIGITS := digits:
              float(x);
            end_proc:

The float approximation of the following value x suffers from numerical cancellation. In particular, for DIGITS = 9 no internal guard digits are available, and the value computed by float has only 3 correct leading digits. Float is used to approximate x with 30 digits. The result is displayed with only 9 digits because of the value DIGITS = 9 valid outside the procedure. However, all displayed digits are correct:

>> x := PI^7 - exp(80131/10000): DIGITS := 9: 
   float(x), Float(x, 30)
                        0.0277910233, 0.0277894265
>> delete Float, x, DIGITS:

Background

Changes




Do you have questions or comments?


Copyright © SciFace Software GmbH & Co. KG 2000