Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ftoc_-_a_fahrenheit_to_celsius_converter [2011/12/16 21:08]
thomaslocke
ftoc_-_a_fahrenheit_to_celsius_converter [2012/03/06 22:20] (current)
cvanvliet fixed a few grammar erros
Line 7: Line 7:
 Before we start, we need to do a little preparation. First create the following directory/​file structure somewhere on your computer: Before we start, we need to do a little preparation. First create the following directory/​file structure somewhere on your computer:
  
-  ​$ mkdir FtoC +<code bash> 
-  $ cd FtoC +$ mkdir FtoC 
-  $ mkdir exe objects +$ cd FtoC 
-  $ touch ftoc.adb ftoc.gpr+$ mkdir exe objects 
 +$ touch ftoc.adb ftoc.gpr 
 +</​code>​
  
 The above should leave you with the following contents in the //FtoC// directory: The above should leave you with the following contents in the //FtoC// directory:
Line 85: Line 87:
  
 =====  Compile And Run FtoC  ===== =====  Compile And Run FtoC  =====
-If you use the excellent [[http://​libre.adacore.com/​libre/​|GPS IDE]], the compiling is a simple matter of pressing //F4// to compile the project, and //​Shift+F2//​ to execute it. If you're not using [[http://​libre.adacore.com/​libre/​|GPS]],​ then do this instead:+If you use the excellent [[http://​libre.adacore.com/​libre/tools/gps/|GPS IDE]], the compiling is a simple matter of pressing //F4// to compile the project, and //​Shift+F2//​ to execute it. If you're not using [[http://​libre.adacore.com/​libre/tools/gps/|GPS]], then do this instead:
  
-  ​$ gnatmake -P ftoc.gpr+<code bash> 
 +$ gnatmake -P ftoc.gpr 
 +</​code>​
  
 You should see some output scroll by: You should see some output scroll by:
Line 167: Line 171:
  
 ====  The FtoC declarations ​ ==== ====  The FtoC declarations ​ ====
- 
 Next we have this code: Next we have this code:
  
Line 189: Line 192:
 That right there is one of the biggest selling points of Ada: The ability to create your own types, with your own constraints. It might not seem like a big deal but, believe me, it is. In this case we've created a new [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-2-2.html|subtype]] of the built-in subtype [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-5-4.html|Natural]]. We've constrained the type's range to //0 .. 212//, meaning that objects declared as a //​Fahrenheit_Degree_Range//​ can **never** go below 0 or above 212. If a value outside this range is assigned to an object of the //​Fahrenheit_Degree_Range//​ type, a //​Constraint_Error//​ exception is raised. That right there is one of the biggest selling points of Ada: The ability to create your own types, with your own constraints. It might not seem like a big deal but, believe me, it is. In this case we've created a new [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-2-2.html|subtype]] of the built-in subtype [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-5-4.html|Natural]]. We've constrained the type's range to //0 .. 212//, meaning that objects declared as a //​Fahrenheit_Degree_Range//​ can **never** go below 0 or above 212. If a value outside this range is assigned to an object of the //​Fahrenheit_Degree_Range//​ type, a //​Constraint_Error//​ exception is raised.
  
-With the //​Fahrenheit_Degree_Range//​ type in place, we direct our attention to the declaration and assignment of the //Fahr// variable. If you've never seen this syntax before or it makes no sense to you, please read the [[Variables|and Constants]] article on this Wiki, and then return here.+With the //​Fahrenheit_Degree_Range//​ type in place, we direct our attention to the declaration and assignment of the //Fahr// variable. If you've never seen this syntax before or it makes no sense to you, please read the [[Variables and Constants]] article on this Wiki, and then return here.
  
 The //Fahr// variable is of the //​Fahrenheit_Degree_Range//​ type and it's initial value is 0. Why 0? Because we assign it the value //​Fahrenheit_Degree_Range'​First//,​ and the //'​First//​ part equals the first value in the range constraint of the type, in this case 0. Consequently the value for //​Fahrenheit_Degree_Range'​Last//​ is 212. The //Fahr// variable is of the //​Fahrenheit_Degree_Range//​ type and it's initial value is 0. Why 0? Because we assign it the value //​Fahrenheit_Degree_Range'​First//,​ and the //'​First//​ part equals the first value in the range constraint of the type, in this case 0. Consequently the value for //​Fahrenheit_Degree_Range'​Last//​ is 212.
  
-Lets take a look at the final three object declarations:​+Let'​s ​take a look at the final three object declarations:​
  
-<source lang="ada">+<code ada>
 Factor ​  : constant ​ := 5.0 / 9.0; Factor ​  : constant ​ := 5.0 / 9.0;
 Offset ​  : constant ​ := 32; Offset ​  : constant ​ := 32;
 Step     : constant ​ := 1; Step     : constant ​ := 1;
-</source>+</code>
  
-What's going on here? Why are there no //type// associated with any of those declarations?​ Well, if you've read the [[Variables|and Constants]] article, you will know that these constants are called [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-3-2.html|named numbers]] and their //type// is called an [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-4-1.html|universal type]]. Named numbers can be of any size and precision.+What's going on here? Why are there no //type// associated with any of those declarations?​ Well, if you've read the [[Variables and Constants]] article, you will know that these constants are called [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-3-2.html|named numbers]] and their //type// is called an [[http://​www.adaic.com/​standards/​05rm/​html/​RM-3-4-1.html|universal type]]. Named numbers can be of any size and precision.
  
 The //Factor// and //Offset// constants are used in the Fahrenheit-to-Celsius calculation,​ and //Step// define how many conversions we do in the program. The //Factor// and //Offset// constants are used in the Fahrenheit-to-Celsius calculation,​ and //Step// define how many conversions we do in the program.
  
 ====  The FtoC body  ==== ====  The FtoC body  ====
- 
 With the declarations out of the way, we turn our attention to the body of the program: With the declarations out of the way, we turn our attention to the body of the program:
  
-<source lang="ada">+<code ada>
 begin begin
    loop    loop
Line 222: Line 224:
    end loop;    end loop;
 end FtoC; end FtoC;
-</source>+</code>
  
 The reserved word //begin// signifies the beginning of the //body// and that same body ends with the final //end FtoC//. Between those two, we have a bunch of statements. The reserved word //begin// signifies the beginning of the //body// and that same body ends with the final //end FtoC//. Between those two, we have a bunch of statements.
  
 ====  The loop  ==== ====  The loop  ====
- 
 The first one is the //loop// statement. Loops come in many different shapes in Ada, each of which obeys the basic premise of The first one is the //loop// statement. Loops come in many different shapes in Ada, each of which obeys the basic premise of
  
-<source lang="ada">+<code ada>
 loop loop
-   some statements+   --  ​some statements
 end loop; end loop;
-</source>+</code>
  
 Loops can be terminated using the //exit// keyword: Loops can be terminated using the //exit// keyword:
  
-<source lang="ada">+<code ada>
 loop loop
-   some statements+   --  ​some statements
    if X = Y then    if X = Y then
       exit;       exit;
    end if;    end if;
 end loop; end loop;
-</source>+</code>
  
 This construction is so common that a shorter version has been made available: This construction is so common that a shorter version has been made available:
  
-<source lang="ada">+<code ada>
 loop loop
-   some statements+   --  ​some statements
    exit when X = Y;    exit when X = Y;
 end loop; end loop;
-</source>+</code>
  
 It is this last version we use in the **FtoC** program and we exit the loop when //Fahr// equals the //'​Last//​ value of the //​Fahrenheit_Degree_Range//​ type. It is this last version we use in the **FtoC** program and we exit the loop when //Fahr// equals the //'​Last//​ value of the //​Fahrenheit_Degree_Range//​ type.
  
 ====  FtoC output - putting integers on the screen ​ ==== ====  FtoC output - putting integers on the screen ​ ====
- 
 Immediately after the //loop// statement we encounter the //Put// procedure: Immediately after the //loop// statement we encounter the //Put// procedure:
  
-<source lang="ada">+<code ada>
 Put (Item  => Fahr, Width => Fahrenheit_Degree_Range'​Width);​ Put (Item  => Fahr, Width => Fahrenheit_Degree_Range'​Width);​
-</source>+</code>
  
 We know from the declaration that //Fahr// is a subtype of //​Natural//,​ which in turn is a subtype of //​Integer//,​ so the call to //Put// on this line actually calls //​Ada.Integer_Text_IO.Put//​. As you can see, we give //Put// two parameters: //Item// and //Width//. The meaning of //Item// should be obvious: It's the integer we want to output, in our case the //Fahr// variable. ​ We know from the declaration that //Fahr// is a subtype of //​Natural//,​ which in turn is a subtype of //​Integer//,​ so the call to //Put// on this line actually calls //​Ada.Integer_Text_IO.Put//​. As you can see, we give //Put// two parameters: //Item// and //Width//. The meaning of //Item// should be obvious: It's the integer we want to output, in our case the //Fahr// variable. ​
Line 272: Line 272:
 The //'​Width//​ attribute returns the maximum width of the type, so if we change the //​Fahrenheit_Degree_Range//​ later on, we wouldn'​t have to do a single thing about this call to //Put//; it would simply adjust itself accordingly. The //'​Width//​ attribute returns the maximum width of the type, so if we change the //​Fahrenheit_Degree_Range//​ later on, we wouldn'​t have to do a single thing about this call to //Put//; it would simply adjust itself accordingly.
  
-Lets do some tests with various //Width// parameters:+Let'​s ​do some tests with various //Width// parameters:
  
-<source lang="ada">+<code ada>
 Put (Item  => Fahr); --  Default Width parameter Put (Item  => Fahr); --  Default Width parameter
-</source>+</code>
  
 The output now looks like this: The output now looks like this:
Line 289: Line 289:
 Lots of wasted space there. This is because //Put// now sets aside space for the //​Integer//,​ which is the type //​Fahrenheit_Degree_Range//​ is derived from. Let's try with 0: Lots of wasted space there. This is because //Put// now sets aside space for the //​Integer//,​ which is the type //​Fahrenheit_Degree_Range//​ is derived from. Let's try with 0:
  
-<source lang="ada">+<code ada>
 Put (Item  => Fahr, Width => 0); --  Minimum required characters for the integer Put (Item  => Fahr, Width => 0); --  Minimum required characters for the integer
-</source>+</code>
  
 And the output: And the output:
  
- 0 -17.78 +  ​0 -17.78 
- 1 -17.22 +  1 -17.22 
- 2 -16.67 +  2 -16.67 
- 3 -16.11 +  3 -16.11 
- 9 -12.78 +  9 -12.78 
- 10 -12.22 +  10 -12.22 
- 11 -11.67 +  11 -11.67 
- ​99 ​ 37.22 +  99  37.22 
- ​100 ​ 37.78 +  100  37.78 
- ​101 ​ 38.33 +  101  38.33 
- ...+  ...
  
 Unfortunately for readability,​ the //Fahr// integer literal is no longer right-justified. Each number is given the exact width necessary to hold it and no more. Unfortunately for readability,​ the //Fahr// integer literal is no longer right-justified. Each number is given the exact width necessary to hold it and no more.
Line 311: Line 311:
 Let's try it with a //Width// that is wide enough for some of the //Fahr// values, but not all of them: Let's try it with a //Width// that is wide enough for some of the //Fahr// values, but not all of them:
  
-<source lang="ada">+<code ada>
 Put (Item  => Fahr, Width => 2); --  Minimum width of 2. Expands if necessary Put (Item  => Fahr, Width => 2); --  Minimum width of 2. Expands if necessary
-</source>+</code>
  
 This outputs: This outputs:
  
-  ​0 -17.78 +   0 -17.78 
-  1 -17.22 +   ​1 -17.22 
-  2 -16.67 +   ​2 -16.67 
-  9 -12.78 +   ​9 -12.78 
- 10 -12.22 +  10 -12.22 
- 11 -11.67 +  11 -11.67 
- ​98 ​ 36.67 +  98  36.67 
- ​99 ​ 37.22 +  99  37.22 
- ​100 ​ 37.78 +  100  37.78 
- ​101 ​ 38.33 +  101  38.33 
- ​102 ​ 38.89 +  102  38.89 
- ​103 ​ 39.44 +  103  39.44 
- ...+  ...
  
 As you can see, the single digit values are right-justified and padded with 1 space, the two-digit values come out even, but the rest of the results are expanded to hold the third character. As you can see, the single digit values are right-justified and padded with 1 space, the two-digit values come out even, but the rest of the results are expanded to hold the third character.
Line 336: Line 336:
 With //Put// for integer types out of the way, we move on to the next //Put//> With //Put// for integer types out of the way, we move on to the next //Put//>
  
-<source lang="ada">+<code ada>
 Put (Item => Factor * Float (Fahr - Offset), Put (Item => Factor * Float (Fahr - Offset),
      Fore => 4,      Fore => 4,
      ​Aft ​ => 2,      ​Aft ​ => 2,
      ​Exp ​ => 0);      ​Exp ​ => 0);
-</source>+</code>
  
 The //Item// parameter for this call to //Put// is a float, because //Factor// is a [[Variables_and_Constants#​Named_numbers | named number]] that contains a decimal point and the expression //Fahr - Offset// is converted to a float using the //Float (Fahr - Offset)// expression. So when calling this //Put//, we're actually calling //​Ada.Float_Text_IO.Put//​. The //Item// parameter for this call to //Put// is a float, because //Factor// is a [[Variables_and_Constants#​Named_numbers | named number]] that contains a decimal point and the expression //Fahr - Offset// is converted to a float using the //Float (Fahr - Offset)// expression. So when calling this //Put//, we're actually calling //​Ada.Float_Text_IO.Put//​.
Line 347: Line 347:
 The //Fore// parameter gives the minimum character count necessary to output the value preceding the decimal point. As with //Width// for the integer types, //Fore// will automatically expand if necessary. //Aft// sets the precision after the decimal point, in this case 2. And finally //Exp// sets the exponent field size. A value of //Exp => 0// signifies that no exponent will be output. Anything other than zero will output the exponent symbol "​E",​ a +/-, and the digit(s) of the exponent. Note: The value of //Exp// should not be less than zero! The //Fore// parameter gives the minimum character count necessary to output the value preceding the decimal point. As with //Width// for the integer types, //Fore// will automatically expand if necessary. //Aft// sets the precision after the decimal point, in this case 2. And finally //Exp// sets the exponent field size. A value of //Exp => 0// signifies that no exponent will be output. Anything other than zero will output the exponent symbol "​E",​ a +/-, and the digit(s) of the exponent. Note: The value of //Exp// should not be less than zero!
  
-Lets try a few different combinations:​+Let'​s ​try a few different combinations:​
  
-<source lang="ada">+<code ada>
 Put (Item => Factor * Float (Fahr - Offset), Put (Item => Factor * Float (Fahr - Offset),
      Fore => 10,      Fore => 10,
      ​Aft ​ => 4,      ​Aft ​ => 4,
      ​Exp ​ => 0);      ​Exp ​ => 0);
-</source>+</code>
  
 The output: The output:
Line 374: Line 374:
 Or how about this: Or how about this:
  
-<source lang="ada">+<code ada>
 Put (Item => Factor * Float (Fahr - Offset), Put (Item => Factor * Float (Fahr - Offset),
      Fore => 4,      Fore => 4,
      ​Aft ​ => 2,      ​Aft ​ => 2,
      ​Exp ​ => 1);      ​Exp ​ => 1);
-</source>+</code>
  
 And the output: And the output:
Line 400: Line 400:
 And finally: And finally:
  
-<source lang="ada">+<code ada>
 Put (Item => Factor * Float (Fahr - Offset), Put (Item => Factor * Float (Fahr - Offset),
      Fore => 0,      Fore => 0,
      ​Aft ​ => 1,      ​Aft ​ => 1,
      ​Exp ​ => 0);      ​Exp ​ => 0);
-</source>+</code>
  
 This outputs: This outputs:
  
-   0-17.8 +    ​0-17.8 
-   ​8-13.3 +    8-13.3 
-   ​9-12.8 +    9-12.8 
-  10-12.2 +   ​10-12.2 
-  11-11.7 +   ​11-11.7 
-  31-0.6 +   ​31-0.6 
-  320.0 +   ​320.0 
-  499.4 +   ​499.4 
-  9836.7 +   ​9836.7 
-  9937.2 +   ​9937.2 
- ​10037.8 +  10037.8 
- ​10138.3 +  10138.3 
- ​10238.9 +  10238.9 
- ...+  ...
  
 Which obviously isn't very pretty to look at. Which obviously isn't very pretty to look at.
Line 429: Line 429:
 The last four lines of the **FtoC** program finish our formatting, get us out of here if we are done, and, if not, set the next value of //Fahr// to be converted: The last four lines of the **FtoC** program finish our formatting, get us out of here if we are done, and, if not, set the next value of //Fahr// to be converted:
  
-<source lang="ada">+<code ada>
    ​New_Line;​    ​New_Line;​
    exit when Fahr = Fahrenheit_Degree_Range'​Last;​    exit when Fahr = Fahrenheit_Degree_Range'​Last;​
    Fahr := Fahr + Step;    Fahr := Fahr + Step;
 end FtoC; end FtoC;
-</source>+</code>
  
 The single call to //​New_Line//​ is the reason we have to make //​Ada.Text_IO//​ available to the **FtoC** program using //with Ada.Text_IO//​. What //​New_Line//​ does is output a single line feed. Running the program without this call to //​New_Line//​ would result in output looking like this: The single call to //​New_Line//​ is the reason we have to make //​Ada.Text_IO//​ available to the **FtoC** program using //with Ada.Text_IO//​. What //​New_Line//​ does is output a single line feed. Running the program without this call to //​New_Line//​ would result in output looking like this:
Line 442: Line 442:
 The //​New_Line//​ procedure accepts a //Spacing// parameter, meaning you can do this to output consecutive line feeds: The //​New_Line//​ procedure accepts a //Spacing// parameter, meaning you can do this to output consecutive line feeds:
  
-<source lang="ada">+<code ada>
 New_Line (Spacing => 5); New_Line (Spacing => 5);
-</source>+</code>
  
 Or simply Or simply
  
-<source lang="ada">+<code ada>
 New_Line (5); New_Line (5);
-</source>+</code>
  
-We've already discussed the //exit when// method of [[FtoC_-_A_Fahrenheit_to_Celsius_converter#​The_loop | terminating a loop]], and the final statement is merely a simple counter. The value of //Fahr// is incremented with //Step// on each iteration of the loop. When //Fahr// equals //​Fahrenheit_Degree_Range'​Last//,​ the loop is terminated.+We've already discussed the //exit when// method of [[FtoC_-_A_Fahrenheit_to_Celsius_converter#​The_loop|terminating a loop]], and the final statement is merely a simple counter. The value of //Fahr// is incremented with //Step// on each iteration of the loop. When //Fahr// equals //​Fahrenheit_Degree_Range'​Last//,​ the loop is terminated.
  
 The final line, //end Ftoc;//, signifies the end of the program. There'​s nothing more to do and nothing more to see. Control is handed back to whatever called the program in the first place, and life goes on. The final line, //end Ftoc;//, signifies the end of the program. There'​s nothing more to do and nothing more to see. Control is handed back to whatever called the program in the first place, and life goes on.

Navigation