Rundungsfehler

[1]:
import numpy as np
from floatMemoryRepresentation import float2bin

Problem

Wir betrachten folgendes schönes Beispiel zum Rundungsproblem aufgrund der endlichen Digits der Zahlendarstellung:

[2]:
r1 = np.arange(0,0.3,0.1)
r1
[2]:
array([0. , 0.1, 0.2])

ABER:

[3]:
r2 = np.arange(1,1.3,0.1)
r2
[3]:
array([1. , 1.1, 1.2, 1.3])

Was passiert hier?

Das Problem besteht darin, dass 0.1 mit endlich vielen Bits nicht exakt dargestellt werden kann. In der Darstellung wird aufgerundet und wir erhalten etwas mehr als 0.1 exakt:

[4]:
float2bin(0.1,length=64)
[4]:
'0011111110111001100110011001100110011001100110011001100110011010'

Mit MPFR können wir 0.1 mit beliebiger Anzahl Bits leicht berechnen (verfügbar mit ‚pip install gmpy2‘):

[5]:
from gmpy2 import mpfr
[6]:
mpfr('0.1',precision=100)
[6]:
mpfr('0.10000000000000000000000000000002',100)

Unter der Verwendung einer 100Bit Darstellung folgt für float(0.1) die effektive Zahl

[7]:
mpfr(float(0.1),precision=100)
[7]:
mpfr('0.10000000000000000555111512312578',100)

Wird nun 3 mal 0.1 mit 52 Bit addiert so erhält man folgende Zahl binär dargestellt:

[8]:
float2bin(3*0.1,length=64)
[8]:
'0011111111010011001100110011001100110011001100110011001100110100'

Welche jedoch kleiner ist als die 52Bit Binäre Darstellung von 0.3:

[9]:
float2bin(0.3,length=64)
[9]:
'0011111111010011001100110011001100110011001100110011001100110011'

Im Fall von 1+3*0.1 ist dem nicht so, hier erhalten wir die exakt identische interne 52Bit Darstellung:

[10]:
float2bin(1+3*0.1,length=64)
[10]:
'0011111111110100110011001100110011001100110011001100110011001101'
[11]:
float2bin(1.3,length=64)
[11]:
'0011111111110100110011001100110011001100110011001100110011001101'

Merke: will man in einer while Schleife inkrementell bis zu einem bestimmten Wert iterieren, wobei das Inkrement dt Teiler der Grenze T ist, so muss man sehr vorsichtig mit der Abfrage t < T sein. Es ist besser t < T + dt/2 zu benutzen.