BINARY_FLOAT
bzw. BINARY_DOUBLE
und eine mögliche Fehlerquelle. Der folgende anonyme PL/SQL-Block demonstriert das Problem: declare v_value binary_double := 0.0d; begin for i in 1 .. 10 loop v_value := v_value + 0.1d; end loop; if (v_value = 1.0d) then dbms_output.put_line('v_value = 1.0'); else dbms_output.put_line('v_value != 1.0'); end if; end; /
v_value != 1.0Das Ergebnis verwundert, denn man erwartet, dass
10
mal 0,1
genau 1
ergibt. Die Ursache liegt in der binären Darstellung von 0,1
; die Datentypen besitzen eben "nur" eine binäre Genauigkeit.Statt einem Vergleich auf Gleichheit, der bei Gleitkommazahlen generell nicht zu empfehlen ist, überprüft man, ob die absolute Abweichung zum Vergleichswert sehr gering ist. Die gewählte Genauigkeit ist je nach Anwendung verschieden; zum Beispiel 10-8.
Durch eine Anpassung des vorherigen PL/SQL-Blocks erhält man nun das erwartete Ergebnis:
declare v_value binary_double := 0.0d; begin for i in 1 .. 10 loop v_value := v_value + 0.1d; end loop; if (abs(v_value - 1.0d) < 1e-8d) then dbms_output.put_line('v_value = 1.0'); else dbms_output.put_line('v_value != 1.0'); end if; end; /
v_value = 1.0Zur Vereinfachung könnte man diese Funktionalität in eine benannte Funktion auslagern:
create or replace function equal( p_value_in in binary_double, p_comparison_value_in in binary_double, p_precision_in in binary_double default 1e-8d ) return boolean is begin return abs(p_value_in - p_comparison_value_in) < p_precision_in; end equal; /
Keine Kommentare:
Kommentar veröffentlichen