From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,bb791bffed99d85a X-Google-Attributes: gid103376,public From: geert@fozzie.sun3.iaf.nl (Geert Bosch) Subject: Re: Help with type conversion needed Date: 1996/01/09 Message-ID: <4cseli$epa@fozzie.sun3.iaf.nl> X-Deja-AN: 134548781 distribution: world references: <4ckmb7$vo0@flood.weeg.uiowa.edu> <4cnivs$m1k@flood.weeg.uiowa.edu> <4cq6ku$l5a@flood.weeg.uiowa.edu> organization: La Calandre Infortunee newsgroups: comp.lang.ada Date: 1996-01-09T00:00:00+00:00 List-Id: In article <4cq6ku$l5a@flood.weeg.uiowa.edu> Nate wrote: `` Right, and this is why I don't want it to be a noop. If I have a range of values from -32768 to 32767, and I want to shift that range to 0 to 65535, simply doing a noop is NOT sufficient.. i.e. -32768 maps to 0 : and 32767 maps to 65535. -1 should map to 32767, NOT 65535.'' There are at least two logical solutions: 1) I don't care about the way my conversion is done. I just specify the result I want and hope the compiler is smart. 2) Compilers may be good, but this audio-sample processing software I am writing needs optimum peformance and I know how to handle this conversion: it can be done with one exclusive-or, so I'll show this in my algorithm. For the first case it makes sense to declare an intermediate type, which can have all values of both the signed and the unsigned type. Once you have converted the signed integer to de intermediate type, you can do the addition and then you can savely convert the new value to the unsigned integer type. You want get errors with range checking, but the compiler might insert range checks if it isn't smart. For the second case the most logical way of doing the conversion is to use a modular type. Modular types are very nice for doing bit-level operations on integers. Any compiler should generate efficient code for modulo 2**N types. Below is a complete program which shows both approaches and does some checks to show the algorithms work well. What I'm really interested in, is the relative efficiency of both methods when compiled by actual Ada compilers. For example, does Method_A use range checks in GNAT? Does method B only generate a XOR instruction when used inline? Greetings, Geert BTW: test might not be such a good name for the program, because it conflicts with the Unix command 'test' === cut here for test.adb ============================================= with Text_IO; with Unchecked_Conversion; -- only needed for Method_B procedure Test is use Text_IO; type Signed_16 is range -2**15..2**15 - 1; for Signed_16'Size use 16; type Unsigned_16 is range 0..2**16 - 1; for Unsigned_16'Size use 16; -- One way to convert type Signed_16 to Unsigned_16 function To_Unsigned_16_A(S : Signed_16) return Unsigned_16 is type Conversion_Range_16 is range -2**15..2**16 - 1; begin return Unsigned_16(Conversion_Range_16(S) + 2**15); end To_Unsigned_16_A; -- Another way to convert type Signed_16 to Unsigned_16 function To_Unsigned_16_B(S : Signed_16) return Unsigned_16 is type Modular_16 is mod 2**16; function To_Modular is new Unchecked_Conversion(Signed_16, Modular_16); function To_Unsigned is new Unchecked_Conversion(Modular_16, Unsigned_16); begin return To_Unsigned(To_Modular(S) xor 16#8000#); end To_Unsigned_16_B; -- Function that only does a conversion if both methods' results agree function To_Unsigned_16(S : Signed_16) return Unsigned_16 is U_A : Unsigned_16 := To_Unsigned_16_A(S); U_B : Unsigned_16 := To_Unsigned_16_B(S); begin if U_A /= U_B then Put_Line("Conversion functions disagree on signed integer " & Signed_16'Image(S)); raise Program_Error; end if; return U_A; end To_Unsigned_16; Test_Cases : array (Integer range <>) of Signed_16 := (-32768, -32767, -1, 0, 1, 32767); U, U_A, U_B : Unsigned_16; S : Signed_16; begin Put_Line("Checking test cases:"); for I in Test_Cases'Range loop S := Test_Cases(I); Put_Line(" Converting signed 16-bit integer " & Signed_16'Image(S) & " to an unsigned 16-bit integer"); U_A := To_Unsigned_16_A(S); U_B := To_Unsigned_16_B(S); Put_Line( " Method A gives " & Unsigned_16'Image(U_A) & ", " & "Method B gives " & Unsigned_16'Image(U_B) ); end loop; Put_Line("Checking complete range"); for I in Signed_16'Range loop U := To_Unsigned_16(I); end loop; Put_Line("Method A produces same results as Method B"); end Test; -- -- E-Mail: geert@sun3.iaf.nl -- Phone: +31-53-4303054 -- E-Mail: geert@sun3.iaf.nl Phone: +31-53-4303054