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