Ada için yeni ve sabit nokta "delta" türlerini deniyorum. Özellikle, ben bir 32-bit delta türü aralığı 0.0 .. 1.0 oluşturduk. Bununla birlikte, belirli değerleri kare çizmeye çalıştığımda, bir CONSTRAINT_ERROR alıyorum. Bildiğim kadarıyla, belirtilen aralığımda olmamalı. Bu hatanın eşiği sqrt(1/2)
olarak görünüyor. MinGW-w64 sürüm 4.8.0'dan GNAT kullanıyorum.Sabit nokta türü doğru şekilde çarpılmıyor
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;
Çıktı
Testi kodu (tümü hiçbir uyarı/hata ile gnatmake <file>
şeklinde derler) belirli bir sayıya kadar .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
Her nasılsa, val
ile çarpma tek başına CONSTRAINT_ERROR ... 'ı açıklayan bir negatif sayı verdi ... ... ama boşver, neden ilk etapta negatif bir sayı alıyorum?
Sonra kare alma numaraları başarısız başladı hangi nokta için test etmeye karar verdi, bu yüzden şu pasajı yazdı:
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;
ve aşağıdaki çıktıyı var:
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#
Yani, sqrt(1/2)
, tekrar karşılaştık. Birisi bana kodumun bunu neden yaptığını açıklayabilir mi? Doğru şekilde çoğaltmak için bir yolu var mı?
Son geçerli ve ilk geçersiz değerlerin * karelerinin * onaltılık ve ikili değerlerini de yazdırmaya değer. Bir hata gibi _feels_ uygulama "başlık altında" bir 32-bit (imzalı) tamsayı kullanarak kısa kesimi alır. Ben delta = 1.0/2 ** 31 ve 1.0/2 ** 33 (aynı aralıkta) denemek için eğimli olurdu. İkincisi daha geniş bir iç türü zorlayabilir veya derlenemez. –
Bu deltaları denedim ve her ikisi de görkemli bir şekilde çalışıyorlar (ikincisi sadece '' Boyut => 32 'yan tümcesini kaldırırken; aksi halde hata derleme). Orijinal delta için, programa ne zaman bir değer atamaya çalıştığımı sorduğumda neden bir "CONSTRAINT_ERROR" yükselttiğini merak ettim. Ancak, -gnato ile yeniden derlediğimde, aslında bu değerleri kabul etmediğini fark ettim. İşaret biti ile uzaklaşmanın bir yolu var mı yoksa farklı bir delta kullanmak zorunda mıyım? – ericmaht