Hello and Help:
I have a table lookup function that is called 3 times by a procedure, and only the last call results in a return of a value. I have tried everything I could think of to remedy the error, but I believe that I have made a basic coding error that I do not recognize and I cannot figure it out.
The function is declared at the end of the Type area, just before the Private declaration. It is as follows: “ Function GammaLookup(GN : Double) : Double; â€.
The actual function is a lengthy table, only the first and last parts are shown below:
Function TFormMainFormBetaDist01072015.GammaLookup(GN : Double) : Double;
begin
if GN < 0.10 then
begin
if MessageDlg('Data ERROR -- a or b is too small -- less than 0.1, application will be terminated', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then close;
end
else if GN = 0.1 then GammaLookup := 9.51351
else if GN = 0.2 then GammaLookup := 4.59084
else if GN = 0.3 then GammaLookup := 2.99157
else if GN = 0.4 then GammaLookup := 2.21816
else if GN = 0.5 then GammaLookup := 1.77245
else if GN = 0.6 then GammaLookup := 1.48919
else if GN = 0.7 then GammaLookup := 1.29806
else if GN = 0.8 then GammaLookup := 1.16423
else if GN = 0.9 then GammaLookup := 1.06863
else if GN = 1.0 then GammaLookup := 1.00000
else if GN = 1.1 then GammaLookup := 0.951351
|
|
∇
else if GN = 9.4 then GammaLookup := 95809.5
else if GN = 9.5 then GammaLookup := 119292.0
else if GN = 9.6 then GammaLookup := 148696.0
else if GN = 9.7 then GammaLookup := 185551.0
else if GN = 9.8 then GammaLookup := 231792.0
else if GN = 9.9 then GammaLookup := 289868.0
else if GN = 10.0 then GammaLookup := 362880.0
else if GN > 10.0 then
begin
if MessageDlg('Data ERROR -- a or b is greater than 10.0, Exit now?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then close;
end ;
end;
The Function is called from a Procedure called Calculate as follows:
procedure TFormMainFormBetaDist01072015.CalculateBTNClick(Sender: TObject);
//
var
//
begin
//
GammaAlpha := FloatEdit5.value;
Label26.caption := FloatToSTRF(GammaAlpha, ffNumber, 5, 2);
gammaA1 := GammaLookup(GammaAlpha);
Label21.Caption := FloatToStrF(GammaA1, ffNumber, 10, 9);
//
GammaBeta := FloatEdit6.value;
Label28.caption := FloatToSTRF(GammaBeta, ffNumber, 5, 2);
gammaB1 := GammaLookup(GammaBeta);
Label23.Caption := FloatToStrF(GammaB1, ffNumber, 10, 9);
//
GammaAlphaBeta := GammaAlpha + GammaBeta;
Label30.Caption := FloatToStrF(GammaAlphaBeta, ffNumber, 10, 2);
gammaAplusB1 := GammaLookup(GammaAlphaBeta);
Label25.caption := FloatToSTRF(GammaAplusB1, ffNumber, 10, 9);
//
//
|
|
∇
Other code that will utilize the values GammaA1, GammaB1, and GammaAplusB1.
End;
there is a data holding unit as follows:
“unit UnitDataHoldingBeta010172015;
interface
var
//
Many, many variable definitions
|
|
∇
GammaAlpha, GAmmaBeta, GammaAlphaBeta, BetaFunction : double;
GammaA1, GammaB1, GammaAplusB1 : double;
//
//
//
implementation
end.
GammaAlpha, GAmmaBeta, GammaAlphaBeta are input from float edit boxes and all displayed on labels on the main form of the application, and the return values from the function of GammaA1, GammaB1 are displayed as 0.0000000 for both, but the return value for GammaAplusB1 is displayed with the proper value.
I have tried changing the number of calls to the function by // out the call lines for each and combinations of 2. If I // out the calls for GammaB1 and GammaAplusB1, the proper value for GammaA1 is displayed, however, if I // out the calls for GammaA1 and GammaAplusB1, there is not any display (other than 0.000000) for GammaB1. As mentioned above, the proper value for the sum of the two , GammaAplusB1 will display properly.
I have also tried substituting “result†for “GammaLookup†on the right side of the “then†in the else If statements. That did not have any effect.
What am I doing wrong? Any suggestions will be greatly appreciated.
John Shyer
"John Shyer" wrote in message news:710969@forums.embarcadero.com...
>
> if GN < 0.10 then
> begin
> if MessageDlg('Data ERROR -- a or b is too small -- less than
> 0.1, application will be terminated', mtConfirmation, [mbYes, mbNo], 0,
> mbYes) = mrYes then close;
> end
> else if GN = 0.1 then GammaLookup := 9.51351
> else if GN = 0.2 then GammaLookup := 4.59084
[...]
> else if GN = 10.0 then GammaLookup := 362880.0
> else if GN > 10.0 then
> begin
> if MessageDlg('Data ERROR -- a or b is greater than 10.0, Exit
> now?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then close;
> end ;
> end;
Your biggest problem is trying to compare floating point values with
constant values. Floating point values are not exact. For each of your
comparisons you need to use the CompareValue function (it is in the Math
unit).
else if CompareValue(GN, 0.1, 0.01) = 0 then GammaLookup := 9.51351
else if CompareValue(GN, 0.2, 0.01) then GammaLookup := 4.59084
The 3rd parameter to CompareValue is the epsilon - or the level of precision
you require. Essentially that means it will round your values to that
precision before comparing them.
However coding 100 if/else statements like this, beyond being tedious, is
very inefficient, every condition must be tested until the passing condition
is found. There are a couple of alternatives that would perform much better.
If you are using any Delphi version from D2009 on you could use a Dictionary
object (in Generics.Collections unit). If not then this if/else ladder could
at least be changed into a case statement. In either case since you are
using values in a defined range and intervals, these could be promoted to
integers to make the comparisons more efficient. E,g, if using case then:
var
GNI: integer;
begin
[...]
GNI := Trunc(GN * 10); // 0.1 becomes 1, 9.9 becomes 99
case GNI of
1: GammaLookup := 9.51351
2: GammaLookup := 4.59084
[...]
100: GammaLookup := 362880.0
else
begin
MessageDlg( ....
end;
end;
If you can use the TDictionary class I would advise it, then you simply add
the entries one time when program starts and the lookup becomes one line:
GammaLookup := BetaDict[GNI];
The dictionary would be:
BetaDict: TDictionary;
....
BetaDict := TDictionary.Create;
BetaDict.Add(1, 9.51351);
BetaDict.Add(2, 4.59084);
[...]
--
Wayne Niddery
"You know what they call alternative medicine that has been proven to work?
Medicine." - Tim Minchin
On 23/01/2015 00:19, Just JJ wrote:
> On Thu, 22 Jan 2015 13:20:38 -0800, John Shyer wrote:
>
> It's mainly caused by float number rounding issue.
>
> In GammaLookup(), you're comparing GN variable with float constants. In
> Delphi, a float constant is an Extended type, and comparing two values with
> different float types can lead to incorrect result. Thus, if GN is 0.4, GN
> <> 0.4.
>
> I would suggest converting the value in GN to Extended then round it to one
> fractional digit (since you're working with and expecting one fractional
> digit value) *even* if it's looks like it only have one fractional digit
> already. e.g.:
>
> var XGN: Extended;
> begin
> XGN:= Round(GN * 10) / 10;
> If XGN < 1.0 then
> .
> .
> else if XGN = 0.1 then ...
> else if XGN = 0.2 then ...
> .
> .
> else if XGN > 10.0 then
> .
> .
> end;
>
I would store each of your values (RHS of the 'thens') in a const array
inside the function as:
const GL: array[1..100] of Double = ( );
Then reference this by Result:=GL[Round(GN*10)];
You would, of course, need to test for Round(GN*10)<1 and
Round(GN*10)>100 prior to referencing the array.
Cheers,
Gerald.
On Thu, 22 Jan 2015 13:20:38 -0800, John Shyer wrote:
> Hello and Help:
>
> I have a table lookup function that is called 3 times by a procedure, and only the last call results in a return of a value. I have tried everything I could think of to remedy the error, but I believe that I have made a basic coding error that I do not recognize and I cannot figure it out.
>
> The function is declared at the end of the Type area, just before the Private declaration. It is as follows: “ Function GammaLookup(GN : Double) : Double; â€.
>
> The actual function is a lengthy table, only the first and last parts are shown below:
>
> Function TFormMainFormBetaDist01072015.GammaLookup(GN : Double) : Double;
>
> begin
> if GN < 0.10 then
> begin
> if MessageDlg('Data ERROR -- a or b is too small -- less than 0.1, application will be terminated', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then close;
> end
> else if GN = 0.1 then GammaLookup := 9.51351
> else if GN = 0.2 then GammaLookup := 4.59084
> else if GN = 0.3 then GammaLookup := 2.99157
> else if GN = 0.4 then GammaLookup := 2.21816
> else if GN = 0.5 then GammaLookup := 1.77245
> else if GN = 0.6 then GammaLookup := 1.48919
> else if GN = 0.7 then GammaLookup := 1.29806
> else if GN = 0.8 then GammaLookup := 1.16423
> else if GN = 0.9 then GammaLookup := 1.06863
> else if GN = 1.0 then GammaLookup := 1.00000
> else if GN = 1.1 then GammaLookup := 0.951351
> |
> |
> ∇
> else if GN = 9.4 then GammaLookup := 95809.5
> else if GN = 9.5 then GammaLookup := 119292.0
> else if GN = 9.6 then GammaLookup := 148696.0
> else if GN = 9.7 then GammaLookup := 185551.0
> else if GN = 9.8 then GammaLookup := 231792.0
> else if GN = 9.9 then GammaLookup := 289868.0
> else if GN = 10.0 then GammaLookup := 362880.0
> else if GN > 10.0 then
> begin
> if MessageDlg('Data ERROR -- a or b is greater than 10.0, Exit now?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then close;
> end ;
> end;
>
[snip]
>
> GammaAlpha, GAmmaBeta, GammaAlphaBeta are input from float edit boxes and all displayed on labels on the main form of the application, and the return values from the function of GammaA1, GammaB1 are displayed as 0.0000000 for both, but the return value for GammaAplusB1 is displayed with the proper value.
>
> I have tried changing the number of calls to the function by // out the call lines for each and combinations of 2. If I // out the calls for GammaB1 and GammaAplusB1, the proper value for GammaA1 is displayed, however, if I // out the calls for GammaA1 and GammaAplusB1, there is not any display (other than 0.000000) for GammaB1. As mentioned above, the proper value for the sum of the two , GammaAplusB1 will display properly.
>
> I have also tried substituting “result†for “GammaLookup†on the right side of the “then†in the else If statements. That did not have any effect.
>
> What am I doing wrong? Any suggestions will be greatly appreciated.
> John Shyer
It's mainly caused by float number rounding issue.
In GammaLookup(), you're comparing GN variable with float constants. In
Delphi, a float constant is an Extended type, and comparing two values with
different float types can lead to incorrect result. Thus, if GN is 0.4, GN
<> 0.4.
I would suggest converting the value in GN to Extended then round it to one
fractional digit (since you're working with and expecting one fractional
digit value) *even* if it's looks like it only have one fractional digit
already. e.g.:
var XGN: Extended;
begin
XGN:= Round(GN * 10) / 10;
If XGN < 1.0 then
.
.
else if XGN = 0.1 then ...
else if XGN = 0.2 then ...
.
.
else if XGN > 10.0 then
.
.
end;
Paolo,
I had not thought of that. I have been inputting values with just one decimal place, and in fact the one that went through was actually an double of the form x.0, with out any other decimal parts. If that is the case, the function returned proper values with an input ending in .0 as the decimal part. Now the only way I can see to achieve the proper lookup is to change all of the GN values to be the original ones * 10.0, then input Gn from "calculate" as GN * 10.0. Is there an easier way to do this?
John
> {quote:title=Paolo Valle wrote:}{quote}
> maybe I cannot help you, but what is the expected result of your function if
> the input value is for example 0.11 ?
>
> "John Shyer" ha scritto nel messaggio news:710969@forums.embarcadero.com...
>
> Hello and Help:
>
> I have a table lookup function that is called 3 times by a procedure,
> and only the last call results in a return of a value. I have tried
> everything I could think of to remedy the error, but I believe that I have
> made a basic coding error that I do not recognize and I cannot figure it
> out.
>
> The function is declared at the end of the Type area, just before the
> Private declaration. It is as follows: “ Function GammaLookup(GN :
> Double) : Double; â€.
>
> The actual function is a lengthy table, only the first and last parts are
> shown below:
>
> Function TFormMainFormBetaDist01072015.GammaLookup(GN : Double) : Double;
>
> begin
> if GN < 0.10 then
> begin
> if MessageDlg('Data ERROR -- a or b is too small -- less than
> 0.1, application will be terminated', mtConfirmation, [mbYes, mbNo], 0,
> mbYes) = mrYes then close;
> end
> else if GN = 0.1 then GammaLookup := 9.51351
> else if GN = 0.2 then GammaLookup := 4.59084
> else if GN = 0.3 then GammaLookup := 2.99157
> else if GN = 0.4 then GammaLookup := 2.21816
> else if GN = 0.5 then GammaLookup := 1.77245
> else if GN = 0.6 then GammaLookup := 1.48919
> else if GN = 0.7 then GammaLookup := 1.29806
> else if GN = 0.8 then GammaLookup := 1.16423
> else if GN = 0.9 then GammaLookup := 1.06863
> else if GN = 1.0 then GammaLookup := 1.00000
> else if GN = 1.1 then GammaLookup := 0.951351
> |
> |
> ∇
> else if GN = 9.4 then GammaLookup := 95809.5
> else if GN = 9.5 then GammaLookup := 119292.0
> else if GN = 9.6 then GammaLookup := 148696.0
> else if GN = 9.7 then GammaLookup := 185551.0
> else if GN = 9.8 then GammaLookup := 231792.0
> else if GN = 9.9 then GammaLookup := 289868.0
> else if GN = 10.0 then GammaLookup := 362880.0
> else if GN > 10.0 then
> begin
> if MessageDlg('Data ERROR -- a or b is greater than 10.0, Exit
> now?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then close;
> end ;
> end;
>
>
> The Function is called from a Procedure called Calculate as follows:
>
> procedure TFormMainFormBetaDist01072015.CalculateBTNClick(Sender: TObject);
> //
> var
> //
> begin
> //
> GammaAlpha := FloatEdit5.value;
> Label26.caption := FloatToSTRF(GammaAlpha, ffNumber, 5, 2);
> gammaA1 := GammaLookup(GammaAlpha);
> Label21.Caption := FloatToStrF(GammaA1, ffNumber, 10, 9);
> //
> GammaBeta := FloatEdit6.value;
> Label28.caption := FloatToSTRF(GammaBeta, ffNumber, 5, 2);
> gammaB1 := GammaLookup(GammaBeta);
> Label23.Caption := FloatToStrF(GammaB1, ffNumber, 10, 9);
> //
> GammaAlphaBeta := GammaAlpha + GammaBeta;
> Label30.Caption := FloatToStrF(GammaAlphaBeta, ffNumber, 10,
> 2);
> gammaAplusB1 := GammaLookup(GammaAlphaBeta);
> Label25.caption := FloatToSTRF(GammaAplusB1, ffNumber, 10,
> 9);
> //
> //
> |
> |
> ∇
> Other code that will utilize the values GammaA1, GammaB1, and GammaAplusB1.
>
> End;
>
> there is a data holding unit as follows:
>
> “unit UnitDataHoldingBeta010172015;
>
> interface
>
> var
> //
> Many, many variable definitions
> |
> |
> ∇
> GammaAlpha, GAmmaBeta, GammaAlphaBeta, BetaFunction : double;
> GammaA1, GammaB1, GammaAplusB1 : double;
> //
> //
> //
> implementation
>
> end.
>
>
> GammaAlpha, GAmmaBeta, GammaAlphaBeta are input from float edit boxes and
> all displayed on labels on the main form of the application, and the return
> values from the function of GammaA1, GammaB1 are displayed as 0.0000000 for
> both, but the return value for GammaAplusB1 is displayed with the proper
> value.
>
> I have tried changing the number of calls to the function by // out the call
> lines for each and combinations of 2. If I // out the calls for GammaB1 and
> GammaAplusB1, the proper value for GammaA1 is displayed, however, if I //
> out the calls for GammaA1 and GammaAplusB1, there is not any display (other
> than 0.000000) for GammaB1. As mentioned above, the proper value for the
> sum of the two , GammaAplusB1 will display properly.
>
> I have also tried substituting “result†for “GammaLookup†on the right side
> of the “then†in the else If statements. That did not have any effect.
>
> What am I doing wrong? Any suggestions will be greatly appreciated.
> John Shyer
maybe I cannot help you, but what is the expected result of your function if
the input value is for example 0.11 ?
"John Shyer" ha scritto nel messaggio news:710969@forums.embarcadero.com...
Hello and Help:
I have a table lookup function that is called 3 times by a procedure,
and only the last call results in a return of a value. I have tried
everything I could think of to remedy the error, but I believe that I have
made a basic coding error that I do not recognize and I cannot figure it
out.
The function is declared at the end of the Type area, just before the
Private declaration. It is as follows: “ Function GammaLookup(GN :
Double) : Double; â€.
The actual function is a lengthy table, only the first and last parts are
shown below:
Function TFormMainFormBetaDist01072015.GammaLookup(GN : Double) : Double;
begin
if GN < 0.10 then
begin
if MessageDlg('Data ERROR -- a or b is too small -- less than
0.1, application will be terminated', mtConfirmation, [mbYes, mbNo], 0,
mbYes) = mrYes then close;
end
else if GN = 0.1 then GammaLookup := 9.51351
else if GN = 0.2 then GammaLookup := 4.59084
else if GN = 0.3 then GammaLookup := 2.99157
else if GN = 0.4 then GammaLookup := 2.21816
else if GN = 0.5 then GammaLookup := 1.77245
else if GN = 0.6 then GammaLookup := 1.48919
else if GN = 0.7 then GammaLookup := 1.29806
else if GN = 0.8 then GammaLookup := 1.16423
else if GN = 0.9 then GammaLookup := 1.06863
else if GN = 1.0 then GammaLookup := 1.00000
else if GN = 1.1 then GammaLookup := 0.951351
|
|
∇
else if GN = 9.4 then GammaLookup := 95809.5
else if GN = 9.5 then GammaLookup := 119292.0
else if GN = 9.6 then GammaLookup := 148696.0
else if GN = 9.7 then GammaLookup := 185551.0
else if GN = 9.8 then GammaLookup := 231792.0
else if GN = 9.9 then GammaLookup := 289868.0
else if GN = 10.0 then GammaLookup := 362880.0
else if GN > 10.0 then
begin
if MessageDlg('Data ERROR -- a or b is greater than 10.0, Exit
now?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then close;
end ;
end;
The Function is called from a Procedure called Calculate as follows:
procedure TFormMainFormBetaDist01072015.CalculateBTNClick(Sender: TObject);
//
var
//
begin
//
GammaAlpha := FloatEdit5.value;
Label26.caption := FloatToSTRF(GammaAlpha, ffNumber, 5, 2);
gammaA1 := GammaLookup(GammaAlpha);
Label21.Caption := FloatToStrF(GammaA1, ffNumber, 10, 9);
//
GammaBeta := FloatEdit6.value;
Label28.caption := FloatToSTRF(GammaBeta, ffNumber, 5, 2);
gammaB1 := GammaLookup(GammaBeta);
Label23.Caption := FloatToStrF(GammaB1, ffNumber, 10, 9);
//
GammaAlphaBeta := GammaAlpha + GammaBeta;
Label30.Caption := FloatToStrF(GammaAlphaBeta, ffNumber, 10,
2);
gammaAplusB1 := GammaLookup(GammaAlphaBeta);
Label25.caption := FloatToSTRF(GammaAplusB1, ffNumber, 10,
9);
//
//
|
|
∇
Other code that will utilize the values GammaA1, GammaB1, and GammaAplusB1.
End;
there is a data holding unit as follows:
“unit UnitDataHoldingBeta010172015;
interface
var
//
Many, many variable definitions
|
|
∇
GammaAlpha, GAmmaBeta, GammaAlphaBeta, BetaFunction : double;
GammaA1, GammaB1, GammaAplusB1 : double;
//
//
//
implementation
end.
GammaAlpha, GAmmaBeta, GammaAlphaBeta are input from float edit boxes and
all displayed on labels on the main form of the application, and the return
values from the function of GammaA1, GammaB1 are displayed as 0.0000000 for
both, but the return value for GammaAplusB1 is displayed with the proper
value.
I have tried changing the number of calls to the function by // out the call
lines for each and combinations of 2. If I // out the calls for GammaB1 and
GammaAplusB1, the proper value for GammaA1 is displayed, however, if I //
out the calls for GammaA1 and GammaAplusB1, there is not any display (other
than 0.000000) for GammaB1. As mentioned above, the proper value for the
sum of the two , GammaAplusB1 will display properly.
I have also tried substituting “result†for “GammaLookup†on the right side
of the “then†in the else If statements. That did not have any effect.
What am I doing wrong? Any suggestions will be greatly appreciated.
John Shyer