我是新來的Ada,並且一直在嘗試定點「delta」類型。具體來說,我創建了一個32位三角洲類型範圍0.0 .. 1.0。但是,當我嘗試平方某些值時,我得到一個CONSTRAINT_ERROR。據我所知,這不應該發生在我指定的範圍內。此錯誤的閾值似乎爲sqrt(1/2)
。我使用的是MinGW-w64版本4.8.0中的GNAT。定點類型不能正確乘積
測試代碼(所有的它編譯中的gnatmake <file>
沒有警告/錯誤的形式):
types.ads:
pragma Ada_2012;
with Ada.Unchecked_Conversion;
with Ada.Text_IO;
package Types is
type Fixed_Type is delta 1.0/2**32 range 0.0 .. 1.0
with Size => 32;
type Modular_Type is mod 2**32
with Size => 32;
function Fixed_To_Mod is new Ada.Unchecked_Conversion(Fixed_Type, Modular_Type);
package MIO is new Ada.Text_IO.Modular_IO(Modular_Type);
package FIO is new Ada.Text_IO.Fixed_IO(Fixed_Type);
end Types;
specifics.adb:
pragma Ada_2012;
with Ada.Text_IO;
with Types; use Types;
procedure Specifics is
package TIO renames Ada.Text_IO;
procedure TestValue(val: in Fixed_Type) is
square : Fixed_Type;
begin
square := val * val;
TIO.Put_Line("Value " & Fixed_Type'Image(val) & " squares properly.");
TIO.Put_Line("Square: " & Fixed_Type'Image(square));
TIO.New_Line;
exception
when Constraint_Error =>
TIO.Put_Line("Value " & Fixed_Type'Image(val) & " does not square properly.");
TIO.Put_Line("Square: " & Fixed_Type'Image(val * val));
TIO.Put_Line("Not sure how that worked.");
TIO.New_Line;
end TestValue;
function ParseFixed(s: in String; last: in Natural; val: out Fixed_Type) return Boolean is
l : Natural;
begin
FIO.Get(s(s'First..last), val, l);
return TRUE;
exception
when others =>
TIO.Put_Line("Parsing failed.");
return FALSE;
end ParseFixed;
buffer : String(1..20);
last : Natural;
f : Fixed_Type;
begin
loop
TIO.Put(">>> ");
TIO.Get_Line(buffer, last);
exit when buffer(1..last) = "quit";
if ParseFixed(buffer, last, f) then
TestValue(f);
end if;
end loop;
end Specifics;
輸出特定的.adb:
>>> 0.1
Value 0.1000000001 squares properly.
Square: 0.0100000000
>>> 0.2
Value 0.2000000000 squares properly.
Square: 0.0399999998
>>> 0.4
Value 0.3999999999 squares properly.
Square: 0.1599999999
>>> 0.6
Value 0.6000000001 squares properly.
Square: 0.3600000001
>>> 0.7
Value 0.7000000000 squares properly.
Square: 0.4899999998
>>> 0.75
Value 0.7500000000 does not square properly.
Square: -0.4375000000
Not sure how that worked.
>>> quit
不知何故,乘以val
本身產生了一個負數,這解釋了CONSTRAINT_ERROR ...但是不用擔心,爲什麼我首先得到一個負數?
然後我決定來測試在該平方數開始失敗的地步,所以我寫了下面的代碼片段:
fixedpointtest.adb:
pragma Ada_2012;
with Ada.Text_IO;
with Types; use Types;
procedure FixedPointTest is
package TIO renames Ada.Text_IO;
test, square : Fixed_Type := 0.0;
begin
while test /= Fixed_Type'Last loop
square := test * test;
test := test + Fixed_Type'Delta;
end loop;
exception
when Constraint_Error =>
TIO.Put_Line("Last valid value: " & Fixed_Type'Image(test-Fixed_Type'Delta));
TIO.Put("Hex value: ");
MIO.Put(Item => Fixed_To_Mod(test-Fixed_Type'Delta), Base => 16);
TIO.New_Line;
TIO.Put("Binary value: ");
MIO.Put(Item => Fixed_To_Mod(test-Fixed_Type'Delta), Base => 2);
TIO.New_Line;
TIO.New_Line;
TIO.Put_Line("First invalid value: " & Fixed_Type'Image(test));
TIO.Put("Hex value: ");
MIO.Put(Item => Fixed_To_Mod(test), Base => 16);
TIO.New_Line;
TIO.Put("Binary value: ");
MIO.Put(Item => Fixed_To_Mod(test), Base => 2);
TIO.New_Line;
TIO.New_Line;
end FixedPointTest;
,並得到了以下的輸出:
Last valid value: 0.7071067810
Hex value: 16#B504F333#
Binary value: 2#10110101000001001111001100110011#
First invalid value: 0.7071067812
Hex value: 16#B504F334#
Binary value: 2#10110101000001001111001100110100#
那麼,sqrt(1/2)
,我們再次見面。有人可以向我解釋爲什麼我的代碼是這樣做的嗎?有沒有辦法使它正確地繁殖?
值得打印出最後一個有效值和第一個無效值的*平方*的十六進制值和二進制值。它感覺像一個錯誤,在這個錯誤中,實現使用32位(帶符號)整數的「快捷方式」。我傾向於嘗試delta = 1.0/2 ** 31和1.0/2 ** 33(同樣的範圍)。後者可能會迫使更廣泛的內部類型,或不能編譯。 –
我嘗試了那些deltas,並且都非常出色(僅當刪除'with Size => 32'子句時纔是第二個;否則編譯錯誤)。對於原始增量,我想知道爲什麼每當我嘗試賦值大於等於0.5時程序都不會引發'CONSTRAINT_ERROR'。但是,當我用'-gnato'重新編譯時,我發現它實際上並不接受這樣的值。有沒有辦法消除符號位,還是我被迫使用不同的三角洲? – ericmaht