View Issue Details

IDProjectCategoryView StatusLast Update
0037474PackagesPackagespublic2020-08-10 22:19
Reporterwp Assigned ToBart Broersma  
PrioritynormalSeverityfeatureReproducibilityalways
Status assignedResolutionopen 
Summary0037474: TFloatSpinEditEx not accepting numbers in exponential notation
DescriptionTFloatSpinEditEx (as well as TFloatSpinEdit) swallows characters ('E'', '-') when a value is typed into the edit box in exponential notation. There is no warning message. This way, when the user is not careful enough, his input '1E-6' becomes a '16'.
Steps To ReproducePlace a TFloatSpinEditEx (or TFloatSpinEdit) onto a form and run. Type '1E-6'. The edit value will be 16 afterwards.
TagsNo tags attached.
Fixed in Revisionr63697
LazTarget-
Widgetset
Attached Files

Activities

Bart Broersma

2020-08-03 22:30

developer   ~0124529

(From a discussion in https://forum.lazarus.freepascal.org/index.php/topic,50866.0.html)

Bart Broersma

2020-08-04 22:34

developer   ~0124570

From the value 9007199254740991.00 incrementing the value by 1.0 gives the same value, so at least from that point on it would certainly make sense to display the value in scientific format.

wp

2020-08-04 23:02

developer   ~0124572

I don't understand. Incrementing the value by 1 and displaying the result in exponential format would not show a difference either.

For me, the FloatSpinEditEx is most interesting as an edit control for numeric input in forms with technical reference. For this purpose, input in exponential notation is required because it is easier to enter 1.234E6 than 1234000.

In order to switch from "normal" to exponential display, I think there should be an "ExponentialFormatLimit" property, with a reasonable default value 6. This means that values > 1E6 and < -1E5, as well as between -1E-6 and +1E-6 will get exponential format, all other values will be formatted as usual. In each case the specified decimal places should be applied.

Bart Broersma

2020-08-05 22:12

developer   ~0124585

> I don't understand. Incrementing the value by 1 and displaying the result in exponential format would not show a difference either.

Of course not, but displaying it as 9007199254740991.00 implies a significance that just isn't there.
Displaying this as 9.0072ESomeExponent makes this more intuitive to understand IMO.

> In order to switch from "normal" to exponential display, I think there should be an "ExponentialFormatLimit" property
I agree, but was unable to propose a good name for that.
It should also be possible to turn this feature off (and it should be off by default for backwards compatibility)

We also have to consider negative exponents. It might not make sense always to use the same ExponentialFormatLimit for that.

Also, how much digits do we use when using scientific notation (I don't thin it should depend on the value of Decimals), so maybe we need yet another property for that.

wp

2020-08-05 22:54

developer   ~0124586

> Displaying this as 9.0072ESomeExponent makes this more intuitive to understand IMO.

Absolutely.

--------------

> It should also be possible to turn this feature off (and it should be off by default for backwards compatibility)

It is turned off automatically when it is greater than the largest exponent (308).

-----------------

> We also have to consider negative exponents. It might not make sense always to use the same ExponentialFormatLimit for that.

ok

---------------------

> Also, how much digits do we use when using scientific notation (I don't thin it should depend on the value of Decimals), so maybe we need yet another property for that.

Do you remember we once had this discussion? When the user types "3.141592" at 2 decimal places and later decides to increase the Decimals to 3 should the display switch to 3.142 or stay at 3.140? Now: What is the difference between truncating 3.141592 after two digits to 3.14 and truncating 31459.2 to 3.14E4? This comes down to the basic question: Should the edit store the unrounded input value? Your former decision was: The edit is for input, and the user should see what is stored. While I initially had a different opinion (coming from fpspreadsheet) I finally agree, and I still do.

Bart Broersma

2020-08-07 22:47

developer   ~0124650

r63697 allows input in scientific format.
(Step 1)

wp

2020-08-08 12:05

developer   ~0124663

Thanks, that's the essential piece that I was missing.

Bart Broersma

2020-08-08 13:01

developer   ~0124664

Last edited: 2020-08-08 13:16

View 3 revisions

And now for the optional display as scientific notation...

For positive exponents, this not very complicated.
For negative exponents however, there is a problem.
Say you have DecimalPlaces = 2
ATM when you set Value := 0.004, Text will become 0.00 and Value will cecome 0 as wellThis is becaus, from the ground up, the control was designed with "the text is the value".

Now if we have a negative exponent and we display thes scientifically it will display 4.0E-2, and so will be the value.
This will break backwards compatibility of the control.

So IMO using a limit value for positive exponents is OK, but we can't use the same number for negative exponents.
We should be able to have a separate value for that (maybe also because the user might want to use different limits for positive and negative limits)
Both limits should default to some value (0?) which indicates scientific notation is unwanted.
Alternatively there could be a property UseScientific notation that controles wether or not we apply the limits.
That might be clearer to the end user.
(That would mean 3 new properties)

Bart Broersma

2020-08-08 13:19

developer   ~0124665

I just figured that 0 for a limit implying don't use it, would mean you couldn't have all text (regardless of value) as scientific i.e. 1.0E0.
Yet another conundrum...

Bart Broersma

2020-08-08 13:32

developer   ~0124666

And we would need a Precision property (0..15) controlling the output (of FloatToStrF) as well.

Bart Broersma

2020-08-08 14:33

developer   ~0124668

First try at implementation in r63698.
Did not yet publish the new properties, so that if we decide to rename them in the next days or so, we won;t have form loading issues.

Please test and comment:
- propertynames: OK or do you have a more intuitive suggestion
- default values for properties
- does it work as you would expect

wp

2020-08-08 19:09

developer   ~0124675

I never understood what "Precision" means in FloatToStrF, and only after some experiments I found out that it has the role of Decimals, and the "Decimals" argument determines the count of digits in the exponent. Really confusing.

program Project1;
uses SysUtils;
var
  x: Double;
  i: Integer;
begin
  x := 12345.5678;
  for i := 0 to 10 do
    WriteLn(i, ': ', FloatToStrF(x, ffExponent, i, 1), ', ', FloatToStrF(x, ffExponent, i, 2), ', ', FloatToStrF(x, ffExponent, i, 3), ', ', FloatToStrF(x, ffExponent, i, 10));
  ReadLn;
end.

I think the DecimalPlaces property of TFloatSpinEditEx should be used as to determine the Precision parameter in FloatToStrF. And there should be one more property "ExponentDigits: TExponentDigits = 1..4". Your new Precision property is not needed.

function TCustomFloatSpinEditEx.ValueToStr(const AValue: Double): String;
begin
  ....
      Result := FloatToStrF(GetLimitedValue(AValue), ffExponent, DecimalPlaces+1, ExponentDigits, FFS)
  ...
end;

---------------------------------------

ExponentialFormatLimitPos and ExponentialFormatLimitNeg are not working as expected. I think this is due to the bug in ValueToStr() where the 2nd part of the "or" in the 2nd "if" checks whether Abs(LValue) is > 10**FExponentialFormatLimitNeg, but it should check for "<" than the limit.

---------------------------------------

The interplay of the ExpFormatLimit values and UseScientificNotation is bit difficult to understand. Perhaps it is easier when the boolean useScientificNotation is replaced by DisplayMode = (dmfixed, dmScientifc, dmMixed):
  - dmFixed -- only fixed point representation, as it is in old version
  - dmScientific --- only exponential representation for all numbers
  - dmMixed -- fixed point when abs(value) > 10^ExpFormatLimitNeg and < 10^ExpFormatLimitPos, exponential otherwise.

This would allow to set the defaults for ExponentialFormatLimitPos/Neg to more practical values, e.g. 6 and -6, respectively.

-----------------------------------

I don't think that the example above with 0.004 being rounded to 0.00 or displayed as 4.0E-3 breaks existing code because exponential presentation did not exist before and this issue could not happen.

Bart Broersma

2020-08-08 22:57

developer   ~0124677

Last edited: 2020-08-08 23:09

View 2 revisions

> I think the DecimalPlaces property of TFloatSpinEditEx should be used as to determine the Precision parameter in FloatToStrF.
I disagree: DecmalPlaces = 2 allows for 123456789.12, Using 2 as precision would cut that down to 1,2E+08, which is not very precise.

> And there should be one more property "ExponentDigits: TExponentDigits"
I thought that 2 would be a nice value, if more is needed it will be added automatically.
Defining the range as 1..4 might trigger exceptions in the object inspector if one sets it there to 9?

> ExponentialFormatLimitPos and ExponentialFormatLimitNeg are not working as expected
Hmm, it worked when I tested it, now it doesn't. Your reasoning is right, but now I'm having a strange problem: the expression 10**FExponentialFormatLimitNeg always evaluates to 0,0000000000000000E+0000 for some reason (I put some debug staments inside the procedure and it alwasy outputs 0).
WTF is going on here?

Bart Broersma

2020-08-08 23:10

developer   ~0124678

Last edited: 2020-08-08 23:13

View 2 revisions

OK, 10**negative is always 0 (integer**integer is IntPower?)
Math.Power(10,negative) will give the correct answer.

Fixed in r63700.

Bart Broersma

2020-08-08 23:19

developer   ~0124679

> DisplayMode = (dmfixed, dmScientifc, dmMixed)
Yes, that can be a solution (I considered it), is it really more intuitive?
Ah, I see: UseScientificNotation might imply it would do that always.
(I would suggest dmAutomatic instead of dmMixed though.)

> This would allow to set the defaults for ExponentialFormatLimitPos/Neg to more practical values, e.g. 6 and -6, respectively.
Which is what they are by default now...

Bart Broersma

2020-08-08 23:41

developer   ~0124680

Implemented ExponentDigits in r63701.

wp

2020-08-09 11:40

developer   ~0124688

>> I think the DecimalPlaces property of TFloatSpinEditEx should be used as to determine the Precision parameter in FloatToStrF.
>I disagree: DecmalPlaces = 2 allows for 123456789.12, Using 2 as precision would cut that down to 1,2E+08, which is not very precise.

I see the point. But don't have numbers in fixed format presentation have a precision as well? To me "precision" and "decimal places" are conflicting properties because I consider the "precision" as a property of the number (and its measurement) and not of its presentation. Suppose the value 1.234E3 which has a precision of 4, i.e. 4 valid digits. Taking the word "precision" seriously, the value can only be displayed as 1234 in fixed format. Setting DecimalPlaces to 2 would display it in fixed format as 1234.00 which is incorrect because it would imply that it has 6 valid digits!

Since "DecimalPlaces" is well-established we should avoid the word "Precision" at all. If you want to distinguish between decimal places for fixed and for exponential format, wouldn't this semantic problem be avoided by renaming your "Precision" property to "DecimalPlacesExp" (and reducing its value by 1)? Or Add least add least some "Exp" prefix/suffix, like "ExpPrecision", to indicate that it applies to exponential format alone.

wp

2020-08-09 11:48

developer   ~0124689

> > DisplayMode = (dmfixed, dmScientifc, dmMixed)
> Yes, that can be a solution (I considered it), is it really more intuitive?
> Ah, I see: UseScientificNotation might imply it would do that always.
> (I would suggest dmAutomatic instead of dmMixed though.)

In the current solution, I could not find a way to turn on exponential display for all numbers. I am thinking of these possibilities (untested):

function TCustomFloatSpinEditEx.ValueToStr(const AValue: Double): String;
var
  LValue: Double;
begin
  LValue := GetLimitedValue(AValue);
  case FDisplayMode of
    dmAutomatic:
      if (Abs(LValue) > Power(10,FExponentialFormatLimitPos)) or
         (Abs(LValue) < Power(10,FExponentialFormatLimitNeg)) then
        Result := FloatToStrF(GetLimitedValue(AValue), ffExponent, FPrecision, FExponentDigits, FFS)
      else
        Result := FloatToStrF(LValue, ffFixed, 20, DecimalPlaces, FFS);
    dmFixed:
      Result := FloatToStrF(LValue, ffFixed, 20, DecimalPlaces, FFS);
    dmExponential:
      Result := FloatToStrF(GetLimitedValue(AValue), ffExponent, FPrecision, FExponentDigits, FFS)
  end;
end;

Bart Broersma

2020-08-09 13:20

developer   ~0124691

Last edited: 2020-08-09 13:27

View 3 revisions

Implemented TDisplayMode in r63705 (before I saw the previous note, and voila, almost exactly the same code).
Please test.

wp

2020-08-09 19:13

developer   ~0124703

Thanks, looks good. Except for value =0 which seems to require a special treatment in the dmAutomatic case because it is displayed as scientific 0.000000E+00 while it should be fixed as 0.00 (in my opinion)

  case FDisplayMode of
    dmAutomatic:
      if (LValue <> 0) and ((Abs(LValue) > Power(10,FExponentialFormatLimitPos)) or
         (Abs(LValue) < Power(10,FExponentialFormatLimitNeg))) then
        Result := FloatToStrF(GetLimitedValue(AValue), ffExponent, FPrecision, FExponentDigits, FFS)
      else
        Result := FloatToStrF(LValue, ffFixed, 20, DecimalPlaces, FFS);

Bart Broersma

2020-08-09 23:20

developer   ~0124705

Well, if 0.00 is below the FExponentialFormatLimitNeg it should be displayed as scientific notation, by definition of the working of these limits?
Otherwise we will require ye another property to control this (or a set of options), because I guarantee you that people will complain.

wp

2020-08-09 23:37

developer   ~0124706

Is the logics in my code wrong?
- when LValue is not zero apply the ExponentialFormatLimits if Abs(LValue) > 10^ExpLimitPos or Abs(LValue < 10^ExpLimitPos.
- in all other cases: use fixed format, in particular including LValue = 0. i.e. in dmAutomatic mode the zero will never be displayed as exponential although the value is less than 10^ExpLimitNeg. I cannot imagine that somebody spinning from -2 to 2 would want to see -2.00, -1.00, 0.000000E+00, 1.00, 2.00 instead of -2.00, -1.00, 0.00, 1.00, 2.00.

Bart Broersma

2020-08-10 09:42

developer   ~0124713

Last edited: 2020-08-10 09:45

View 3 revisions

> Is the logics in my code wrong?
No.

But I think you cannot satisfy everbody with the current setup.
I could extend the TDisplayMode with dmScientificZeroFixed and dmAutoZeroFixed: that would give users the control.
(Feel free to suggest better names)

B.t.w is comparing a double to zero "(LValue<>0)" OK, or is it better to use "not SameValue(LValue, 0.0)"?

wp

2020-08-10 11:17

developer   ~0124716

> I could extend the TDisplayMode with dmScientificZeroFixed and dmAutoZeroFixed: that would give users the control.

OK. Maybe this: As a user not knowing about the inner workinngs of the control, I would expect dmAuto to be the more "general" setting and expect to see '0.00' there instead of in dmAutoZeroFixed. But anyway...

----------------

> B.t.w is comparing a double to zero "(LValue<>0)" OK, or is it better to use "not SameValue(LValue, 0.0)"?

Good point. The "SameValue()" will probably be required during spinning where the Increment is added to / subtracted from the current value again and againg, and the exact zero may be missed due to accumulated rounding errors. Users wishing to enter tiny values such as 5E-18 ( 5 atto-Farad, some parasitic capacitance in memory-chip design) will switch to dmScientific anyway.

This reminds me of another wish: How about allowing to add multiplier characters to the numbers, i.e. enter 1.2k instead of 1200 or 1.2n instead of 1.2E-9? This would be an interesting feature for electrical engineers. Something for the future, of course...

Bart Broersma

2020-08-10 11:49

developer   ~0124718

So, in Scientific mode zero displaying as 0.00E+00 is OK, we can expect users to expect this? In that case dmScientificZeroFixed is not needed.

> How about allowing to add multiplier characters to the numbers, i.e. enter 1.2k instead of 1200 or 1.2n instead of 1.2E-9
Better make a new class that inherits from TFloatSpinEditEx for this.
You would need to override EditKeyPress, ValueToStr and StrToValue.

I do think this should then not go into LazControls, but maybe in CCR.

Bart Broersma

2020-08-10 16:16

developer   ~0124739

As it turns out SameValue is not necessary: since this is about typing/conevrting, a text of '0.0' will be converted to a double with all zero's as bitpattern.
Implemented in r63712.

wp

2020-08-10 17:00

developer   ~0124740

Thank you. For me, the modification is complete (after publishing the new properties).

Bart Broersma

2020-08-10 22:19

developer   ~0124745

I'll let it open for a while, just to remind me the properties must be published (I'll wait a bit).

Issue History

Date Modified Username Field Change
2020-08-03 19:01 wp New Issue
2020-08-03 19:01 wp Status new => assigned
2020-08-03 19:01 wp Assigned To => Bart Broersma
2020-08-03 22:30 Bart Broersma Note Added: 0124529
2020-08-04 22:34 Bart Broersma Note Added: 0124570
2020-08-04 23:02 wp Note Added: 0124572
2020-08-05 22:12 Bart Broersma Note Added: 0124585
2020-08-05 22:13 Bart Broersma Severity minor => feature
2020-08-05 22:13 Bart Broersma LazTarget => -
2020-08-05 22:54 wp Note Added: 0124586
2020-08-07 22:47 Bart Broersma Note Added: 0124650
2020-08-08 12:05 wp Note Added: 0124663
2020-08-08 13:01 Bart Broersma Note Added: 0124664
2020-08-08 13:15 Bart Broersma Note Edited: 0124664 View Revisions
2020-08-08 13:16 Bart Broersma Note Edited: 0124664 View Revisions
2020-08-08 13:19 Bart Broersma Note Added: 0124665
2020-08-08 13:32 Bart Broersma Note Added: 0124666
2020-08-08 14:33 Bart Broersma Note Added: 0124668
2020-08-08 14:34 Bart Broersma Status assigned => feedback
2020-08-08 19:09 wp Note Added: 0124675
2020-08-08 19:09 wp Status feedback => assigned
2020-08-08 22:57 Bart Broersma Note Added: 0124677
2020-08-08 23:09 Bart Broersma Note Edited: 0124677 View Revisions
2020-08-08 23:10 Bart Broersma Note Added: 0124678
2020-08-08 23:13 Bart Broersma Note Edited: 0124678 View Revisions
2020-08-08 23:14 Bart Broersma Fixed in Revision => r63697, r63698, r63700
2020-08-08 23:19 Bart Broersma Note Added: 0124679
2020-08-08 23:19 Bart Broersma Fixed in Revision r63697, r63698, r63700 => r63697
2020-08-08 23:41 Bart Broersma Note Added: 0124680
2020-08-09 11:40 wp Note Added: 0124688
2020-08-09 11:48 wp Note Added: 0124689
2020-08-09 13:20 Bart Broersma Note Added: 0124691
2020-08-09 13:27 Bart Broersma Note Edited: 0124691 View Revisions
2020-08-09 13:27 Bart Broersma Note Edited: 0124691 View Revisions
2020-08-09 19:13 wp Note Added: 0124703
2020-08-09 23:20 Bart Broersma Note Added: 0124705
2020-08-09 23:37 wp Note Added: 0124706
2020-08-10 09:42 Bart Broersma Note Added: 0124713
2020-08-10 09:43 Bart Broersma Note Edited: 0124713 View Revisions
2020-08-10 09:45 Bart Broersma Note Edited: 0124713 View Revisions
2020-08-10 11:17 wp Note Added: 0124716
2020-08-10 11:49 Bart Broersma Note Added: 0124718
2020-08-10 16:16 Bart Broersma Note Added: 0124739
2020-08-10 17:00 wp Note Added: 0124740
2020-08-10 22:19 Bart Broersma Note Added: 0124745