7

私は Ada が初めてで、固定小数点の「デルタ」型を試しています。具体的には、32 ビットのデルタ型の範囲 0.0 .. 1.0 を作成しました。ただし、特定の値を二乗しようとすると、CONSTRAINT_ERROR が発生します。私の知る限り、指定した範囲では発生しないはずです。このエラーのしきい値は のようsqrt(1/2)です。MinGW-w64 バージョン 4.8.0 の GNAT を使用しています。

gnatmake <file>テストコード (すべて警告/エラーなしでコンパイルされます):

タイプ.広告:

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;

仕様.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;

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 を説明しています...しかし気にしないでください。そもそもなぜ負の数が得られるのでしょうか?

次に、数値の二乗が失敗し始めたポイントをテストすることにしたので、次のスニペットを書きました。

固定点テスト.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)またお会いしましょう。誰かが私のコードがこれを行っている理由を説明してもらえますか? うまく増殖させる方法はありますか?

4

1 に答える 1