The formula we have for the speed of sound is:
The ratio of specific heats for air, we are given, is 1.4. The universal gas constant, we know, is 8.314 kg m2 per mole °K sec2. The temperature is the input.
The units of a(T) need to be meters per second. The units of T are °K, so the units of RT are kg m2 mole-1 sec-2. We need to know what a mole of air is.
A mole is a gram molecular weight: molecular hydrogen (H2) has a molecular weight of about 2, and so one mole is 2 grams. The atmosphere is largely molecular nitrogen (N2), with a molecular weight of 28: one mole of molecular nitrogen is therefore 28g, or .028kg. The atmosphere actually contains oxygen (molecular weight 32), carbon dioxide (molecular weight 48), and other gasses, bringing its average molecular weight to about 29.1. The air gas constant is therefore:
Rair = 8.314 kg m2 (29.1g)-1 °K-1 sec-2 = 286 m2 °K-1 sec-2
The speed of sound, for a particular temperature T in °K, is therefore:
This will be a one-line program.
The temperature range in which we are interested is about -70°F to +70°F, or about 216°K to 294°K. We actually want the speed of sound as a function of the height. Fortunately, we already have the temperature as a function of height, and speed of sound as a function of temperature, so we can easily obtain the velocity of sound as a function of height. This, too, will be a one-line program.
The speed of sound as a function of temperature is a one-line routine. The speed of sound as a function of height is a two-line routine, one of which is invoking the speed of sound as a function of temperature routine. Should we actually invoke the routine, or simply replicate the one-line computation? This seemingly innocent question is actually a question about our development philosophy and values.
The arguments for replicating the code are straightforward. Repeating the computation would take less space than would calling the routine to compute it. Repeating the computation would take less execution time than would calling the routine to compute it. Efficiency, therefore, argues for replicating the code. The arguments against replicating the code are similarly straightforward. Duplicated code is a maintainability risk, as there are two places to update in the event of a change. So here we have a known and quantifiable efficiency gain to be made, and the price is an unquantifiable increase in risk — not an actual harm, but only a risk of eventual harm.
Clearly, “avoiding an unknown risk of an unknown something bad happening at an unknown future time” is a weaker position than “a measurable gain right now.” Most managers would choose the “good business practice” of the measurable gain right now, and would justify this in ROI grounds. However, this simplistic ROI-based reasoning has three fundamental flaws.
The first flaw is assuming the investment discount rate applies to future expenses. In the computer field, computers get constantly cheaper and programmers get constantly more expensive — both relative to the computers, and relative to the rest of the world. Delaying most expenses has a positive ROI: if I put aside the money for a new chair in the bank and can delay purchasing the new chair for a year, the chair will cost about the same but I will have more money. However, delaying a programming expense has a negative, not a positive, ROI: if I put aside the money for a new program in the bank and can delay the development of a new piece of software for a year, the program will cost more than the amount in the bank at the end of the year.
The second flaw lies in assuming that the effort going into the repair is comparable to the effort going into avoiding the need for a repair. This is simply not true — studies show that the effort and expense required to make a repair to deployed software is thousands of times greater than the effort and expense required to avoid the need to repair in the first place. The overall stages of creating a program are obtaining requirements, specifying the functions of the program, designing the program, coding the program, testing the program, and deploying the program. At each stage, the cost to repair a defect goes up by a factor of ten or so.
The third flaw is assuming development is an investment. Development is an investment only when maintainability is the highest value in the development process. Otherwise, development is only an expense, as the object produced — the program — is disposable, rather than durable.
Most code — certainly all custom code — is in fact a liability, not an asset. It represents an expense stream, not an income stream. To turn code into an asset, a great deal of care must be taken to make the code maintainable, modifiable, and reliable.
Applying this reasoning to our choice here, the decision is clear. We will call the speed of sound as a function of temperature routine, not replicate it. We want our code to be an asset, not a liability.
Finally, we will need to test our routines. There is really nothing we can do, other than graph the value and see if it seems reasonable. The velocity of sound routine gives us the speed of sound in meters per second. One meter is 3.281 feet, or 0.0006214 miles, and one second is 0.0002778 hours; so one meter per second is 2.237 miles per hour. At the ground, in our standard 59°F day, this is 759.6 miles per hour; we have a vague memory that the speed of sound is about 750 miles per hour, so this seems reasonable. The minimum speed of sound would be in the -70°F region, where the speed would be 658.6 miles per hour. So our “unit test” in this instance is just a graphing program.
We can easily code the two speed of sound routines, as follows.
Program VSOUNDT (26 bytes):
; Program VSOUNDT ; ; Compute the speed of sound in meters per second for air, based on ; the temperature in degrees Kelvin. ; ; Variables: ; A on entry is the temperature in degrees Kelvin, and on exit is the ; speed of sound in meters per second. ; ; Symbols: ; sqrt is square root symbol ; -> is assignment arrow 20.01sqrtA->A ; Compute speed of sound
Program VSOUNDH (35 bytes):
; Program VSOUNDH ; ; Compute the speed of sound in meters per second for air, based on ; the height in meters. ; ; Variables: ; A height in meters [entry, input to TEMP]; height in meters [output ; from TEMP, input to VSOUNDT]; speed of sound in meters per second ; [output from VSOUNDT, exit] ; ; Symbols: Prog "TEMP" ; Convert height in meters to temperature in Kelvin Prog "VSOUNDT" ; Compute speed of sound based on temperature
Similarly, the unit test is just a graphing routine.
Program UTVSOUND (114 bytes):
; Program UTVSOUND ; ; Graph the speed of sound as a function of height ; ; Variables: ; A is input to and result from VSOUNDH ; B is height in feet ; C is velocity of sound in miles per hour ; ; Symbols: ; -> is assignment arrow ; <> is not equal to relational ViewWindow 0,100000,10000,650,800,50 ; Set the view window for the graph For 0->B To 100000 Step 1000 ; Loop through altitudes in 1000 foot increments .3048B->A ; Get the altitude in meters Prog "VSOUNDH" ; Get the velocity of sound in meters/second 2.237A->C ; Convert to miles/hour Plot B,C ; Graph velocity of sound against height If B<>0 ; If this is not the first point, Then Line ; connect it with a line to the previous point IfEnd ; [End of test if this is the first point] Next ; [End of loop through altitudes]
When we run this program, we get the following graph of the velocity of sound as a function of the height:
Note that the Y axis goes from 650 to 800 miles per hour, and so excludes zero. The calculator shows the omission of zero by not drawing an X axis. The calculator draws only the tick marks for every 10,000 feet.
The two speed of sound routines and the graphing unit test are easy enough to write, and follow.
Private Function VSoundTemp(ByVal Kelvin As Single) As Single ' FUNCTIONAL DESCRIPTION: ' ' Computes the speed of sound in air as meters per second for a ' specified temperature in degrees Kelvin. ' ' FORMAL PARAMETERS: ' ' Temperature.rf.v - The temperature in degrees Kelvin for which ' the speed of sound in air is to be computed. ' ' IMPLICIT INPUTS: ' ' None. ' ' IMPLICIT OUTPUTS: ' ' None. ' ' RETURN VALUE: ' ' The speed of sound in meters per second for air at the ' specified temperature. ' ' SIDE EFFECTS: ' ' None. ' VSoundTemp = 20.01 * Sqr(Kelvin) End Function
Private Function VSoundHeight(ByVal Meters As Single) As Single ' FUNCTIONAL DESCRIPTION: ' ' Computes the speed of sound in air as meters per second for a ' specified height in meters. ' ' FORMAL PARAMETERS: ' ' Height.rf.v - The height in meters for which the speed of ' sound is to be computed. ' ' IMPLICIT INPUTS: ' ' None. ' ' IMPLICIT OUTPUTS: ' ' None. ' ' RETURN VALUE: ' ' The speed of sound in meters per second for air at the ' specified height. ' ' SIDE EFFECTS: ' ' None. ' VSoundHeight = VSoundTemp(Temp(Meters)) End Function
Private Sub UTVSound() ' FUNCTIONAL DESCRIPTION: ' ' Unit tests the VSoundH routine. ' ' Graphs the velocity of sound as a function of height. ' ' FORMAL PARAMETERS: ' ' None. ' ' IMPLICIT INPUTS: ' ' None. ' ' IMPLICIT OUTPUTS: ' ' plt - The CalculatorGraph control. ' The text of the current document. ' ' RETURN VALUE: ' ' None. ' ' SIDE EFFECTS: ' ' None. ' Dim Feet As Single Dim VSound As Single plt.ViewWindow 0, 100000, 10000, 650, 800, 50 For Feet = 0 To 100000 Step 1000 VSound = 2.237 * VSoundHeight(0.3048 * Feet) plt.Plot Feet, VSound If Feet <> 0 Then plt.PlotLine End If DoEvents Next Feet WriteLn "Velocity of sound unit test run." End Sub
Running the unit test routine gives us a graph very similar to that given by the calculator.
Once again, it is time to move on.
Copyright © 2002 Brian Hetrick
Page last updated 10 February 2002.
Building Blocks I
Control Flow II
A First Program
Data Structures I
Building Blocks II
Data Structures II