Unexpected Ada Type Compatibility

105 Views Asked by At

Why are Volts, Amps, and Ohms compatible?


with ada.text_io; use ada.text_io;
                                                                    
procedure main is                                                   
    type Volts is delta 1.0 / 2.0 ** 12 range -45_000.0 .. 45_000.0;
    type Amps is delta 1.0 / 2.0 ** 16 range -1_000.0 .. 1_000.0;   
    type Ohms is delta 0.125 range 0.0 .. 1.0E8;                    
                                                                    
    V : Volts := 1.0;                                               
    A : Amps := 1.0;                                                
    R1 : Ohms := 1.0;                                               
    R2 : Ohms := 1.0;                                               
                                                                   
begin                                             
                     
    v := A * (R1 + R2);
                       
    put_line(V'Img);   
                       
end main;  

If the types the types are defined as new Float I get the following exception during compilation:


main.adb:22:12: error: invalid operand types for operator "*"
main.adb:22:12: error: left operand has type "Amps" defined at line 5
main.adb:22:12: error: right operand has type "Ohms" defined at line 6

I expected the use of type with Volts to define a new type that was incompatible with the other types as it wasn't an explicit subtype of the fixed point type.

2

There are 2 best solutions below

0
Niklas Holsti On BEST ANSWER

Multiplication and division with operands of different fixed-point types is explicitly allowed (predefined) in the Ada standard since Ada 95 -- see http://www.ada-auth.org/standards/22rm/html/RM-4-5-5.html, paragraph 18 -- but only in a context where the result is also expected to be of some fixed-point type (see paragraph 19.1/2). Addition and subtraction between different fixed-point types is not predefined, and of course different fixed-point types are not compatible in eg. parameters or assignment.

As to why * and / are allowed between different types, I don't have a clear answer. One of the relevant Ada Issues (http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ais/ai-00364.txt?rev=1.15) has this brief comment by Randy Brukardt: "... the Ada 95 rules came about because people complained about having to write a type conversion in: A := B * 5.0; which was felt to make Ada look bad.".

The same AI also has comments critical of the new rule... so opinions differ.

2
Jeffrey R. Carter On

The canonical representation for a fixed-point value is an integer; the represented value is the stored integer multiplied by the small for the type (for decimal fixed-point types, the small and the delta are the same; for ordinary fixed-point types, they may differ).

So for a type like

type FP is delta 0.001 digits 10;

the values 12.345 and 67.890 would be stored as 12_345 and 67_890, respectively. When you multiply them, you get 838_102_050, which represents 838.102_050, with a small of 0.000_001. So multiplying values of the same type yields a value of a different type. Something similar applies when the operands are of different types. The language therefore defines multiplication and division in terms of universal_fixed, though the result must be converted, explicitly or implicitly (as in your example), to a named type, as Holsti pointed out.

Similar issues arise with division; 67_890 / 12_345 yields 5, with a small of 1.0.

Another consequence of this is that you can multiply or divide a fixed-point value by an integer and get a value of the same fixed-point type without any adjustment: 3 * 12_345 = 37_035, which represents 37.035 = 3 * 12.345. Such multiplication and division operators for type Integer are defined by the language.