comp.lang.ada
 help / color / mirror / Atom feed
* Help with low level Ada
@ 2011-03-17 14:31 Syntax Issues
  2011-03-17 17:46 ` Shark8
  2011-03-17 17:55 ` Jeffrey Carter
  0 siblings, 2 replies; 6+ messages in thread
From: Syntax Issues @ 2011-03-17 14:31 UTC (permalink / raw)


I am translating a C math library and need help with low level
operations - setting individual bytes, and-ing data types, and bit
shifting. Below are the problems I have run in to.

---------------------------------------------------------------------------------------
Setting individual bytes
---------------------------------------------------------------------------------------
typedef float			vec_t;
typedef vec_t			vec3_t[3];
unsigned ColorNormalize (vec3_t rgb){
	unsigned	c;
	float		max;
	...
	((byte *)&c)[0] = rgb[0] * max;
	((byte *)&c)[1] = rgb[1] * max;
	((byte *)&c)[2] = rgb[2] * max;
	((byte *)&c)[3] = 255;
	return c;
}
function Normalize
	(Red_Green_Blue : in Vector_Color)
	return Integer_Color
	is
	Result  : Integer_Color := 0;
	Maximum : Float_4       := 0.0;
	begin
		...
		return
			-- ???!!??!?!? Byte(Red_Green_Blue(1) * Maximum) +
			-- ???!!??!?!? Byte(Red_Green_Blue(2) * Maximum) +
			-- ???!!??!?!? Byte(Red_Green_Blue(3) * Maximum);
	end Normalize;
---------------------------------------------------------------------------------------
And-ing Data types
---------------------------------------------------------------------------------------
float AngleMod (float angle){
	return (360.0/65536) * ((int)(angle * (65536/360.0)) & 65535);
}
function Mod_Angle
	(Angle : in Float_4)
	return Float_4
	is
	begin
		return (360.0 / 65536.0) * (Integer_4_Signed(Angle * (65536.0 /
360.0)) ---???!?!?!& 65535);
	end Mod_Angle;
---------------------------------------------------------------------------------------
Shifting
---------------------------------------------------------------------------------------
int NearestPowerOfTwo (int number, qboolean roundDown){
	int n = 1;
	if (number <= 0)
		return 1;
	while (n < number)
		n <<= 1;
	if (roundDown){
		if (n > number)
			n >>= 1;
	}
	return n;
}
---???!!?!??!?!?



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with low level Ada
  2011-03-17 14:31 Help with low level Ada Syntax Issues
@ 2011-03-17 17:46 ` Shark8
  2011-03-17 17:59   ` Jeffrey Carter
  2011-03-17 17:55 ` Jeffrey Carter
  1 sibling, 1 reply; 6+ messages in thread
From: Shark8 @ 2011-03-17 17:46 UTC (permalink / raw)


On Mar 17, 8:31 am, Syntax Issues <syntax.iss...@gmail.com> wrote:
> I am translating a C math library and need help with low level
> operations - setting individual bytes, and-ing data types, and bit
> shifting. Below are the problems I have run in to.
>
> ---------------------------------------------------------------------------------------
> Setting individual bytes
> ---------------------------------------------------------------------------------------
> typedef float                   vec_t;
> typedef vec_t                   vec3_t[3];
> unsigned ColorNormalize (vec3_t rgb){
>         unsigned        c;
>         float           max;
>         ...
>         ((byte *)&c)[0] = rgb[0] * max;
>         ((byte *)&c)[1] = rgb[1] * max;
>         ((byte *)&c)[2] = rgb[2] * max;
>         ((byte *)&c)[3] = 255;
>         return c;}
>
> function Normalize
>         (Red_Green_Blue : in Vector_Color)
>         return Integer_Color
>         is
>         Result  : Integer_Color := 0;
>         Maximum : Float_4       := 0.0;
>         begin
>                 ...
>                 return
>                         -- ???!!??!?!? Byte(Red_Green_Blue(1) * Maximum) +
>                         -- ???!!??!?!? Byte(Red_Green_Blue(2) * Maximum) +
>                         -- ???!!??!?!? Byte(Red_Green_Blue(3) * Maximum);
>         end Normalize;
> ---------------------------------------------------------------------------------------
> And-ing Data types
> ---------------------------------------------------------------------------------------
> float AngleMod (float angle){
>         return (360.0/65536) * ((int)(angle * (65536/360.0)) & 65535);}
>
> function Mod_Angle
>         (Angle : in Float_4)
>         return Float_4
>         is
>         begin
>                 return (360.0 / 65536.0) * (Integer_4_Signed(Angle * (65536.0 /
> 360.0)) ---???!?!?!& 65535);
>         end Mod_Angle;
> ---------------------------------------------------------------------------------------
> Shifting
> ---------------------------------------------------------------------------------------
> int NearestPowerOfTwo (int number, qboolean roundDown){
>         int n = 1;
>         if (number <= 0)
>                 return 1;
>         while (n < number)
>                 n <<= 1;
>         if (roundDown){
>                 if (n > number)
>                         n >>= 1;
>         }
>         return n;}
>
> ---???!!?!??!?!?

For bit-shifts there's the Package Interfaces's Shift_Right,
Shift_Left, Shift_Right_Arithmetic, and so forth.

For bits I would prefer to use Array (1..N) Of Boolean, with
Pragma Packed, and using 'Address to overlay it upon the data
you want to bit-manipulate. {It may be better/easier to
overlay an integer or modular type, like if you were low-level
manipulating floating-point data.}

With the bit_array you can not/and/or/xor with the boolean
operations as you normally would:

Letting I_1 & I_2 be unsigned integers XOR-ing them could
be achieved via this:

  Type Bits is Array ( Positive Range <> ) of Boolean;
  Pragma Pack( Bits );

XOR_DATA:
Declare
 B_1 : Bits( I_1'Size );
 For B_1'Address Use I_1'Address;
 Pragma Import( Ada, B_1 ); -- This prevents the initialization
                            -- of B_1, which would destroy the value
of I_1

 B_2 : Bits( I_2'Size );
 For B_2'Address Use I_1'Address;
 Pragma Import( Ada, B_2 );

 Result_B : Bits( Positive'Max(B_1'Size, B_2'Size) );
 Result_I : Some_Unsigned_Integer;
Begin
 For Index in Reverse Result_B'Range Loop
  -- Raises error if B_1'Size /= B_2'Size when invalid indecies are
used.
  Result_B(Index):= B_1(Index) XOR B_2(Index);
 End Loop;

-- Here you would use Result_I as-needed.
End XOR_DATA;

Setting individual bytes is much like the above.



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with low level Ada
  2011-03-17 14:31 Help with low level Ada Syntax Issues
  2011-03-17 17:46 ` Shark8
@ 2011-03-17 17:55 ` Jeffrey Carter
  2011-03-17 19:30   ` Syntax Issues
  1 sibling, 1 reply; 6+ messages in thread
From: Jeffrey Carter @ 2011-03-17 17:55 UTC (permalink / raw)


On 03/17/2011 07:31 AM, Syntax Issues wrote:
> unsigned ColorNormalize (vec3_t rgb){
> 	unsigned	c;
> 	float		max;
> 	...
> 	((byte *)&c)[0] = rgb[0] * max;
> 	((byte *)&c)[1] = rgb[1] * max;
> 	((byte *)&c)[2] = rgb[2] * max;
> 	((byte *)&c)[3] = 255;
> 	return c;
> }
> function Normalize
> 	(Red_Green_Blue : in Vector_Color)
> 	return Integer_Color
> 	is
> 	Result  : Integer_Color := 0;
> 	Maximum : Float_4       := 0.0;
> 	begin
> 		...
> 		return
> 			-- ???!!??!?!? Byte(Red_Green_Blue(1) * Maximum) +
> 			-- ???!!??!?!? Byte(Red_Green_Blue(2) * Maximum) +
> 			-- ???!!??!?!? Byte(Red_Green_Blue(3) * Maximum);
> 	end Normalize;

First, I'd probably do something like

type Color_ID is (Red, Blue, Green);

subtype Natural_Float_4 is Float_4 range 0.0 .. Float_4'Last;

type Vector_Color is array (Color_ID) of Natural_Float_4;

so I can say Red_Green_Blue (Red). (I presume that the components of 
Vector_Color cannot be negative; better to make that clear in the code and 
enforced by the language.)

One approach to this is

type Byte is mod 2 ** 8;

type Color_Bytes is record
    Red    : Byte;
    Green  : Byte;
    Blue   : Byte;
    Unused : Byte;
end record;
for Color_Bytes use
    Red    at 0 range 0 .. 7;
    Green  at 1 range 0 .. 7;
    Blue   at 2 range 0 .. 7;
    Unused at 3 range 0 .. 7;
end record;
for Color_Bytes'Size use Integer_Color'Size;

You may need to change the representation clause to get the components in the 
right places.

function Convert is new Ada.Unchecked_Conversion
    (Source => Color_Bytes, Target => Integer_Color);

Result := Color_Bytes'(Red    => Byte (Red_Green_Blue (Red)    * Maximum),
                        Green  => Byte (Red_Green_Blue (Green)  * Maximum),
                        Blue   => Byte (Red_Green_Blue (Blue)   * Maximum),
                        Unused => Byte'Last);

return Convert (Result);

You missed out the assignment of 255 to the 4th byte.

Another way is to use an array of 4 Bytes that you unchecked convert to the 
result type.

Finally, if you use a modular type from package Interfaces you can shift the 
products into their correct positions and "or" them together. And you can always 
imitate that by multiplying by a power of 2 and adding them together:

Result := Integer_Color (Red_Green_Blue (Red)    * Maximum) * 2 **  0 +
           Integer_Color (Red_Green_Blue (Green)  * Maximum) * 2 **  8 +
           Integer_Color (Red_Green_Blue (Blue)   * Maximum) * 2 ** 16 +
           255 * 2 ** 24;

The compiler will often replace these by shifts.

> float AngleMod (float angle){
> 	return (360.0/65536) * ((int)(angle * (65536/360.0))&  65535);
> }
> function Mod_Angle
> 	(Angle : in Float_4)
> 	return Float_4
> 	is
> 	begin
> 		return (360.0 / 65536.0) * (Integer_4_Signed(Angle * (65536.0 /
> 360.0)) ---???!?!?!&  65535);
> 	end Mod_Angle;

Bitwise "and" is defined for all modular types. The only wrinkle is what happens 
if Angle is negative. If that's not allowed (see Natural_Float_4 above), then 
it's fairly easy:

type Integer_4_Unsigned is mod Integer_4_Signed'Size;

return (360.0 / 65536.0) *
        Float_4 (Integer_4_Unsigned (Angle * (65536.0 / 360.0) ) and 65535);

Otherwise, you need to do some unchecked converting between signed and modular 
types of the same size:

function Convert is new Ada.Unchecked_Conversion
    (Source => Integer_4_Signed, Target => Integer_4_Unsigned);

return (360.0 / 65536.0) *
        Float_4 (Convert (Integer_4_Signed (Angle * (65536.0 / 360.0) ) ) and
                 65535);

(I presume that Integer_4_Signed is 4 bytes from its name, so the result of 
"and"ing that with 65535 will always be non-negative. In that case, there's no 
need to convert back to signed before converting to Float_4.)

> int NearestPowerOfTwo (int number, qboolean roundDown){
> 	int n = 1;
> 	if (number<= 0)
> 		return 1;
> 	while (n<  number)
> 		n<<= 1;
> 	if (roundDown){
> 		if (n>  number)
> 			n>>= 1;
> 	}
> 	return n;
> }

Shift operations are defined for the modular types defined in package 
Interfaces. As mentioned above, the same effect can often be obtained with 
multiplication and division by powers of 2, and the compiler will often replace 
them with shifts:

while N < Number loop
    N := 2 * N;
end loop;

if Round_Down and N > Number then
    N := N / 2;
end if;

You could also use the Log function from Ada.Numerics.Generic_Elementary_Functions:

type Big is digits 15;

package Math is new Ada.Numerics.Generic_Elementary_Functions
    (Float_Type => Big);

N := 2 ** Integer (Math.Log (Big (Number), 2.0) );

if N < Number then
    N := 2 * N;
end if;

if Round_Down and N > Number then
    N := N / 2;
end if;

-- 
Jeff Carter
"We use a large, vibrating egg."
Annie Hall
44



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with low level Ada
  2011-03-17 17:46 ` Shark8
@ 2011-03-17 17:59   ` Jeffrey Carter
  2011-03-20  3:45     ` Shark8
  0 siblings, 1 reply; 6+ messages in thread
From: Jeffrey Carter @ 2011-03-17 17:59 UTC (permalink / raw)


On 03/17/2011 10:46 AM, Shark8 wrote:
>
> Letting I_1&  I_2 be unsigned integers XOR-ing them could
> be achieved via this:

Bitwise "and", "or", "xor", and "not" are defined for all modular types. You can 
simply say

I_1 xor I_2

-- 
Jeff Carter
"We use a large, vibrating egg."
Annie Hall
44



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with low level Ada
  2011-03-17 17:55 ` Jeffrey Carter
@ 2011-03-17 19:30   ` Syntax Issues
  0 siblings, 0 replies; 6+ messages in thread
From: Syntax Issues @ 2011-03-17 19:30 UTC (permalink / raw)


On Mar 17, 1:55 pm, Jeffrey Carter
<spam.jrcarter....@spam.not.acm.org> wrote:
> On 03/17/2011 07:31 AM, Syntax Issues wrote:
>
>
>
>
>
>
>
>
>
> > unsigned ColorNormalize (vec3_t rgb){
> >    unsigned        c;
> >    float           max;
> >    ...
> >    ((byte *)&c)[0] = rgb[0] * max;
> >    ((byte *)&c)[1] = rgb[1] * max;
> >    ((byte *)&c)[2] = rgb[2] * max;
> >    ((byte *)&c)[3] = 255;
> >    return c;
> > }
> > function Normalize
> >    (Red_Green_Blue : in Vector_Color)
> >    return Integer_Color
> >    is
> >    Result  : Integer_Color := 0;
> >    Maximum : Float_4       := 0.0;
> >    begin
> >            ...
> >            return
> >                    -- ???!!??!?!? Byte(Red_Green_Blue(1) * Maximum) +
> >                    -- ???!!??!?!? Byte(Red_Green_Blue(2) * Maximum) +
> >                    -- ???!!??!?!? Byte(Red_Green_Blue(3) * Maximum);
> >    end Normalize;
>
> First, I'd probably do something like
>
> type Color_ID is (Red, Blue, Green);
>
> subtype Natural_Float_4 is Float_4 range 0.0 .. Float_4'Last;
>
> type Vector_Color is array (Color_ID) of Natural_Float_4;
>
> so I can say Red_Green_Blue (Red). (I presume that the components of
> Vector_Color cannot be negative; better to make that clear in the code and
> enforced by the language.)
>
> One approach to this is
>
> type Byte is mod 2 ** 8;
>
> type Color_Bytes is record
>     Red    : Byte;
>     Green  : Byte;
>     Blue   : Byte;
>     Unused : Byte;
> end record;
> for Color_Bytes use
>     Red    at 0 range 0 .. 7;
>     Green  at 1 range 0 .. 7;
>     Blue   at 2 range 0 .. 7;
>     Unused at 3 range 0 .. 7;
> end record;
> for Color_Bytes'Size use Integer_Color'Size;
>
> You may need to change the representation clause to get the components in the
> right places.
>
> function Convert is new Ada.Unchecked_Conversion
>     (Source => Color_Bytes, Target => Integer_Color);
>
> Result := Color_Bytes'(Red    => Byte (Red_Green_Blue (Red)    * Maximum),
>                         Green  => Byte (Red_Green_Blue (Green)  * Maximum),
>                         Blue   => Byte (Red_Green_Blue (Blue)   * Maximum),
>                         Unused => Byte'Last);
>
> return Convert (Result);
>
> You missed out the assignment of 255 to the 4th byte.
>
> Another way is to use an array of 4 Bytes that you unchecked convert to the
> result type.
>
> Finally, if you use a modular type from package Interfaces you can shift the
> products into their correct positions and "or" them together. And you can always
> imitate that by multiplying by a power of 2 and adding them together:
>
> Result := Integer_Color (Red_Green_Blue (Red)    * Maximum) * 2 **  0 +
>            Integer_Color (Red_Green_Blue (Green)  * Maximum) * 2 **  8 +
>            Integer_Color (Red_Green_Blue (Blue)   * Maximum) * 2 ** 16 +
>            255 * 2 ** 24;
>
> The compiler will often replace these by shifts.
>
> > float AngleMod (float angle){
> >    return (360.0/65536) * ((int)(angle * (65536/360.0))&  65535);
> > }
> > function Mod_Angle
> >    (Angle : in Float_4)
> >    return Float_4
> >    is
> >    begin
> >            return (360.0 / 65536.0) * (Integer_4_Signed(Angle * (65536.0 /
> > 360.0)) ---???!?!?!&  65535);
> >    end Mod_Angle;
>
> Bitwise "and" is defined for all modular types. The only wrinkle is what happens
> if Angle is negative. If that's not allowed (see Natural_Float_4 above), then
> it's fairly easy:
>
> type Integer_4_Unsigned is mod Integer_4_Signed'Size;
>
> return (360.0 / 65536.0) *
>         Float_4 (Integer_4_Unsigned (Angle * (65536.0 / 360.0) ) and 65535);
>
> Otherwise, you need to do some unchecked converting between signed and modular
> types of the same size:
>
> function Convert is new Ada.Unchecked_Conversion
>     (Source => Integer_4_Signed, Target => Integer_4_Unsigned);
>
> return (360.0 / 65536.0) *
>         Float_4 (Convert (Integer_4_Signed (Angle * (65536.0 / 360.0) ) ) and
>                  65535);
>
> (I presume that Integer_4_Signed is 4 bytes from its name, so the result of
> "and"ing that with 65535 will always be non-negative. In that case, there's no
> need to convert back to signed before converting to Float_4.)
>
> > int NearestPowerOfTwo (int number, qboolean roundDown){
> >    int n = 1;
> >    if (number<= 0)
> >            return 1;
> >    while (n<  number)
> >            n<<= 1;
> >    if (roundDown){
> >            if (n>  number)
> >                    n>>= 1;
> >    }
> >    return n;
> > }
>
> Shift operations are defined for the modular types defined in package
> Interfaces. As mentioned above, the same effect can often be obtained with
> multiplication and division by powers of 2, and the compiler will often replace
> them with shifts:
>
> while N < Number loop
>     N := 2 * N;
> end loop;
>
> if Round_Down and N > Number then
>     N := N / 2;
> end if;
>
> You could also use the Log function from Ada.Numerics.Generic_Elementary_Functions:
>
> type Big is digits 15;
>
> package Math is new Ada.Numerics.Generic_Elementary_Functions
>     (Float_Type => Big);
>
> N := 2 ** Integer (Math.Log (Big (Number), 2.0) );
>
> if N < Number then
>     N := 2 * N;
> end if;
>
> if Round_Down and N > Number then
>     N := N / 2;
> end if;
>
> --
> Jeff Carter
> "We use a large, vibrating egg."
> Annie Hall
> 44

Excellent, I really appreciate the help.



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with low level Ada
  2011-03-17 17:59   ` Jeffrey Carter
@ 2011-03-20  3:45     ` Shark8
  0 siblings, 0 replies; 6+ messages in thread
From: Shark8 @ 2011-03-20  3:45 UTC (permalink / raw)


On Mar 17, 11:59 am, Jeffrey Carter
<spam.jrcarter....@spam.not.acm.org> wrote:
> On 03/17/2011 10:46 AM, Shark8 wrote:
>
>
>
> > Letting I_1&  I_2 be unsigned integers XOR-ing them could
> > be achieved via this:
>
> Bitwise "and", "or", "xor", and "not" are defined for all modular types. You can
> simply say
>
> I_1 xor I_2
>
> --
> Jeff Carter
> "We use a large, vibrating egg."
> Annie Hall
> 44

Ah, you're right!
perhaps I should have said signed.
{I've been messing with OpenGL's 10- & 11-bit floating-point numbers
and so immediately thought of their exponent & mantissa fields which
you might implement as either modular-types or natural-constrained
subtypes.}



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-03-20  3:45 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-17 14:31 Help with low level Ada Syntax Issues
2011-03-17 17:46 ` Shark8
2011-03-17 17:59   ` Jeffrey Carter
2011-03-20  3:45     ` Shark8
2011-03-17 17:55 ` Jeffrey Carter
2011-03-17 19:30   ` Syntax Issues

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox