Lazarus

Programming => General => Topic started by: flori on March 04, 2021, 01:22:13 pm

Title: case of
Post by: flori on March 04, 2021, 01:22:13 pm
Hi everyone!
I have a small demo which categorize the contents of the leaf (such as apple, apricot leaf, etc)  ... low, medium high

Code: Pascal  [Select][+][-]
  1. Case Round(StringToNumber(edit6.Text)*100) of
  2.    2000..3000: N_res.text:='low';
  3.      End;
  4. case Round(StringToNumber(edit6.Text)*100) of
  5.    3001..4000: N_res.text:='medium';
  6.  End;
  7. if Nlab>40.01 then N_res.text:='high';


The categories (low, medium, high) unfortunately changes many times (every day:(). I put some Edit on the form where we can give  (we can specify) the values  (low: 20-30, medium: n1-n2, high<n)
Does anyone know how can I change code
Code: Pascal  [Select][+][-]
  1. 2000..3000: N_res.text:='low'
to calculate based on what I type (what values) into edit? (categorize based on what I type edits)
I attached demo
Thank you


Title: Re: case of
Post by: Roland57 on March 04, 2021, 01:31:10 pm
Hello! I don't believe it be possible to use "case of" that way.

Maybe you could use the InRange (https://www.freepascal.org/docs-html/rtl/math/inrange.html) function from the Math unit.

Regards.

Roland
Title: Re: case of
Post by: MarkMLl on March 04, 2021, 02:13:23 pm
I agree: the values have to be constant at compilation time.

OP: you've got extra ends in your example: should be something like

Code: Pascal  [Select][+][-]
  1.     Case Round(StringToNumber(edit6.Text)*100) of
  2.        2000..3000: N_res.text:='low';
  3.        3001..4000: N_res.text:='medium'
  4.     otherwise
  5.        if Nlab>40.01 then
  6.          N_res.text:='high'
  7.        else
  8.          N_res.text:='GOK'
  9.      End;
  10.  

MarkMLl
[/code]
Title: Re: case of
Post by: flori on March 04, 2021, 02:53:07 pm
yes. But I would like to change: (see the picture)
instead of codes to read from Edit(s).
Title: Re: case of
Post by: Zvoni on March 04, 2021, 02:56:01 pm
Not possible with Case Of
As Roland said: Use InRange from math
Title: Re: case of
Post by: flori on March 04, 2021, 02:56:32 pm
ok I will try
Title: Re: case of
Post by: Zvoni on March 04, 2021, 03:04:57 pm
quick and dirty (and not tested)
Code: Pascal  [Select][+][-]
  1. Var
  2.   iMin:Integer;
  3.   iMax:Integer;
  4. .
  5. .
  6. .
  7. iMin:=StringToNumber(editLeft.Text)*100;
  8. iMax:=StringToNumber(editRight.Text)*100;
  9.  
  10. If InRange(StringToNumber(edit6.Text)*100, iMin, iMAx) Then Do SomeThing;
  11.  
Title: Re: case of
Post by: flori on March 04, 2021, 03:41:19 pm
Thanks. I tried your code
I modified :unfortunately it's not good either



Code: Pascal  [Select][+][-]
  1. function InRange ..
  2. var
  3.   iMin:real;
  4.   iMax:real;
  5. begin
  6. iMin:=StringToNumber(Edit1.Text);
  7. iMax:=StringToNumber(Edit2.Text);
  8.  
  9. If InRange (Round((StringToNumber(edit6.Text)*100)), iMin, iMAx) then
  10.    N_res.Text:='low' else N_res.Text:='error dose';  

end;

Title: Re: case of
Post by: Kays on March 04, 2021, 03:50:55 pm
I agree: the values have to be constant at compilation time.
Background information: The rationale is that the compiler must be able to verify that all case label values are disjunct, there is no overlap.

[…] Does anyone know how can I change code
Code: Pascal  [Select][+][-]
  1. 2000..3000: N_res.text:='low'
to calculate based on what I type (what values) into edit? (categorize based on what I type edits)[…]
You must “translate”, i.e. displace and scale your values to ranges you know at compile-time, something like:
Code: Pascal  [Select][+][-]
  1. uses
  2.         // for `sign`, but this is not /really/ necessary
  3.         math;
  4.  
  5. type
  6.         category = (low, medium, high);
  7.         categoryLimits = record
  8.                         // values including and above this threshold are `medium`
  9.                         lowMediumThreshold: integer;
  10.                         // values including and above this threshold are `high`
  11.                         mediumHighThreshold: integer;
  12.                 end;
  13.  
  14. function categorization(
  15.                 value: integer;
  16.                 const definition: categoryLimits
  17.         ): category;
  18. begin
  19.         with definition do
  20.         begin
  21.                 assert(lowMediumThreshold < mediumHighThreshold);
  22.                
  23.                 // normalize
  24.                 value := value - lowMediumThreshold;
  25.                 value := floor(value / (mediumHighThreshold - lowMediumThreshold));
  26.                 value := sign(value);
  27.         end;
  28.        
  29.         case value of
  30.                 -1:
  31.                 begin
  32.                         categorization := low;
  33.                 end;
  34.                 0:
  35.                 begin
  36.                         categorization := medium;
  37.                 end;
  38.                 1:
  39.                 begin
  40.                         categorization := high;
  41.                 end;
  42.                 otherwise
  43.                 begin
  44.                         assert(false);
  45.                 end;
  46.         end;
  47. end;
Then you can still use the case language construct.
Title: Re: case of
Post by: flori on March 04, 2021, 03:58:29 pm
Kays: thanks the background info  :)
Title: Re: case of
Post by: flori on March 04, 2021, 05:00:38 pm
unfortunately it does not work really with InRange (sure i don't use it well)?


Title: Re: case of
Post by: glorfin on March 04, 2021, 05:54:58 pm
unfortunately it does not work really with InRange (sure i don't use it well)?
Yes, use of InRange implies use of if then else construct instead of case.
So, you have basically two choices: if then else instead of case, or map your values like Kay suggested. Personally I would use If Then Else with InRange.
Title: Re: case of
Post by: balazsszekely on March 04, 2021, 05:57:58 pm
@flori

You implemented your on version of InRange function which body is empty, remove it, then add math to the uses.  Instead of TEdit use TFloatSpinEdit, you can directly enter float values and set the Min/Max. Much easier this way.
Title: Re: case of
Post by: flori on March 04, 2021, 06:09:41 pm
Yes.
unfortunately for some reason it is miscategorized  (low dose)
is my code wrong?
 
Code: Pascal  [Select][+][-]
  1. var
  2. iMin:Double;
  3. iMax:Double;
  4.                  
  5. iMin:=StringToNumber(Edit1.Text);
  6. iMax:=StringToNumber(Edit2.Text);
  7.  
  8. If InRange (Round((StringToNumber(edit6.Text)*100)), iMin, iMAx) then
  9.    N_res.Text:='low' else N_res.Text:='error dose';
Title: Re: case of
Post by: WooBean on March 06, 2021, 11:36:02 am
Just remark to "case" documentation - we can use ranges not limited to 0..255.

Below some code which I find a self explaining:
Code: Pascal  [Select][+][-]
  1. program project1;
  2. var i:integer;
  3.  
  4. begin
  5.   i:=1024;
  6.  
  7. {$R-} //needed to force compiling line below
  8.   writeln('Result of "',i,' in [1000..1025]" is ',i in [1000..1025]);
  9. //project1.lpr(9,63) Warning: range check error while evaluating constants (1025 must be between 0 and 255)
  10. //project1.lpr(9,57) Warning: range check error while evaluating constants (1000 must be between 0 and 255)
  11. {$R+} //now range checking is turned on
  12.   write('In case selector range value ',i);
  13.   case i of
  14.   1000..1025: writeln(' is between 1000..1025');
  15.   else
  16.     writeln(' is not between 1000..1025'); // never to happen
  17.   end;
  18.  
  19.   i:=1026;
  20.   write('In case selector range value ',i);
  21.   case i of
  22.   1000..1025: writeln(' is between 1000..1025');
  23.   else
  24.     writeln(' is not between 1000..1025'); // never to happen
  25.   end;
  26.  
  27.  
  28.   write('In case selector ranges value ',i);
  29.   case i of
  30.   1000..1025,1030..1032: writeln(' is among ranges 1000..1025,1030..1032');
  31.   else
  32.     writeln(' is not among ranges 1000..1025,1030..1032');
  33.   end;
  34.  
  35.   write('In case selector ranges value ',i);
  36.   case i of
  37.   1000..1005,1025..1032: writeln(' is among ranges 1000..1005,1025..1032');
  38.   else
  39.     writeln(' is not among ranges 1000..1005,1025..1032');
  40.   end;
  41.  
  42.   readln;
  43. end.
  44.  
  45.  
Title: Re: case of
Post by: winni on March 06, 2021, 07:35:27 pm
Hi!

Nice trick for all situations where a set (again and again) is too small.

And

Code: Pascal  [Select][+][-]
  1. (w >= 10000) and (w<=20000)

is inconvenient.

Winni


Title: Re: case of
Post by: winni on March 06, 2021, 09:36:40 pm
Hi!

Question at the edge of this topic.

I can do

Code: Pascal  [Select][+][-]
  1. case frequency of
  2. 16..800: ...
  3. 801..2000: ...
  4. 2001..20000: ...
  5. end; //case
  6.  

So there is a set like mechanism for a range between 16 and 20000.
Why is the same mechanism not used for sets?

I know that old UCSD Pascal used the same mechanism for sets and case. Sets "only" for 0..4095 and case for 0..32767.

So why is fpc not going that way to enlargen sets?

Winni


Title: Re: case of
Post by: Kays on March 06, 2021, 09:51:44 pm
[…] So why is fpc not going that way to enlargen sets?
Delhpi compatibility.

[…]
Code: Pascal  [Select][+][-]
  1. []
  2. class Operator TMyRangeType.in(A:Integer;B:TMyRangeType):Boolean;Inline;
  3. []
Well, “fun fact”: At one point something like 1337 in -42..5040 (https://wiki.freepascal.org/User_Changes_2.6.0#.3COrdinal.3E_in_.3CSet_type.3E_is_now_forbidden) was possible.
Title: Re: case of
Post by: winni on March 06, 2021, 10:59:14 pm
[…] So why is fpc not going that way to enlargen sets?
Delhpi compatibility.


Hi!

I know that "Delphi compatibility" is always the alibi for nearly every bug or restriction.
But this time not.

If you build a superset for the range of a set it does not disturb Delphi compatitbility, because a Delphi mini set would fit into a bigger fpc set. The other way round there might be problems. But this way is seldom.

And it might convince Delphi-Users to switch to  fpc/Lazarus.
( Or UCSD-Pascal).

The 256 element set restriction is a relict of Turbo Pascal and was already old fashioned in these days.

Winni
Title: Re: case of
Post by: Kays on March 06, 2021, 11:50:03 pm
I know that "Delphi compatibility" is always the alibi for nearly every bug or restriction.
But this time not.

If you build a superset for the range of a set it does not disturb Delphi compatitbility, […]
Well, then it isn’t so much about creating conflicts but there just were “more important” Delphi-compatibility-related things, so those were attended first, before creating something new, you know.
The 256 element set restriction is a relict of Turbo Pascal and was already old fashioned in these days.
I absolutely agree with you. The compiler and RTL (https://svn.freepascal.org/cgi-bin/viewvc.cgi/tags/release_3_2_0/rtl/inc/genset.inc?view=markup#l15) do contain code for what’s called “Varset”. I understand the current default set implementations are “small set” and “normal set” in FPC terms (https://wiki.freepascal.org/Type_information#set_definition_(TSetDef)).

I don’t know how to enable/use those “varset”. In revision 8515 (https://svn.freepascal.org/cgi-bin/viewvc.cgi?view=revision&revision=8515) Jonas wrote there were still problems, though.
Title: Re: case of
Post by: winni on March 07, 2021, 12:32:34 am

I don’t know how to enable/use those “varset”. In revision 8515 (https://svn.freepascal.org/cgi-bin/viewvc.cgi?view=revision&revision=8515) Jonas wrote there were still problems, though.

Hi
Thanx  for that info.

Code: Text  [Select][+][-]
  1. Revision 8515 (13 years, 5 months ago)
  2.  


Ok. It just hit puberty and that is always a time of big changes.
So let's hope the best!

What else can I say????

Winni

Title: Re: case of
Post by: PascalDragon on March 07, 2021, 02:48:34 pm
I know that "Delphi compatibility" is always the alibi for nearly every bug or restriction.
But this time not.

If you build a superset for the range of a set it does not disturb Delphi compatitbility, […]
Well, then it isn’t so much about creating conflicts but there just were “more important” Delphi-compatibility-related things, so those were attended first, before creating something new, you know.

The problem is less Delphi-compatibility, but more size. If you have a set of 1024 elements you need 1024 bits aka 128 Byte aka an array of 32 UInt32. Of course one might argue that in today's time that is nothing, but one shouldn't scoff at that either.

That said I'd guess that we'll increase the limit of sets in one of the next major releases.

And case-statements have no restrictions regarding this.

The 256 element set restriction is a relict of Turbo Pascal and was already old fashioned in these days.
I absolutely agree with you. The compiler and RTL (https://svn.freepascal.org/cgi-bin/viewvc.cgi/tags/release_3_2_0/rtl/inc/genset.inc?view=markup#l15) do contain code for what’s called “Varset”. I understand the current default set implementations are “small set” and “normal set” in FPC terms (https://wiki.freepascal.org/Type_information#set_definition_(TSetDef)).

I don’t know how to enable/use those “varset”. In revision 8515 (https://svn.freepascal.org/cgi-bin/viewvc.cgi?view=revision&revision=8515) Jonas wrote there were still problems, though.

The varset helpers are used for any set with more than 32 elements as a bit array will be used for those instead of primitive types.
Title: Re: case of
Post by: winni on March 07, 2021, 03:21:46 pm

The problem is less Delphi-compatibility, but more size. If you have a set of 1024 elements you need 1024 bits aka 128 Byte aka an array of 32 UInt32. Of course one might argue that in today's time that is nothing, but one shouldn't scoff at that either.

That said I'd guess that we'll increase the limit of sets in one of the next major releases.


Hi!

Let's have a look at the Apple II and UCSD Pascal.
We had an OS that fitted in 64 kB (KILO!!).
We had segment procedures for swaping in  and out of the RAM to make a 250 kB executable to fit to that 64kB (for example Adimens DB).
We had two floppy drives and everything was awful slow.

BUT: We had sets for 4096 elements!
That was over 40 years ago!!

I hope the the next development step for sets will not only reach 1024 elements.
That would be only 1 / 4 of UCSD Pascal 40 years ago!

Winni

 
Title: Re: case of
Post by: Blaazen on March 07, 2021, 03:28:47 pm
Sets for more than 256 are listed in future plans since I remember: https://www.freepascal.org/future.html (https://www.freepascal.org/future.html)
Title: Re: case of
Post by: avk on March 07, 2021, 04:23:58 pm
Hi!

@winni, I've already seen you regret about the lack of sets in FPC more than 256 elements several times.
Are you only interested in the built-in set, or is a home-made one suitable?
Title: Re: case of
Post by: winni on March 07, 2021, 07:46:37 pm
@avk

No - I am interestested in a built-in set  inside the fpc ≫ 256 elements.

A workaround with an array of set I made myself.

Winni
Title: Re: case of
Post by: avk on March 07, 2021, 08:01:03 pm
The set, which I meant, almost completely mimics the built-in set and, moreover, can accept Subrange types, including those with a negative lower bound. But if no, then no.
Title: Re: case of
Post by: flori on March 09, 2021, 12:09:00 pm
Thank you everyone.
I managed to solve the problem

Code: Pascal  [Select][+][-]
  1. procedure TfrmLeaf.btnCalculateClick(Sender: TObject);
  2.  
  3.    // local functions visible inside the event method
  4.  
  5.   function IsEmpty(ATxt: TEdit): Boolean;
  6.   begin
  7.     Result := Length(Trim(ATxt.Text)) = 0;
  8.   end;
  9.  
  10.   function InRange(ALab, ALow, AHigh, AVH: TEdit): TValueRange;
  11.   begin
  12.     Result := vrNone;
  13.     if IsEmpty(ALab) or IsEmpty(ALow) or IsEmpty(AHigh) or IsEmpty(AVH) then
  14.       exit;
  15.     Result := vrMedium;
  16.     if Str2Float(ALab.Text) <= Str2Float(ALow.Text) then
  17.       Result := vrLow
  18.     else if Str2Float(ALab.Text) >= Str2Float(AHigh.Text) then
  19.       Result := vrHigh;
  20.   if Str2Float(ALab.Text) >= Str2Float(AVH.Text) then
  21.       Result := vvH;
  22.   end;
  23.  
  24.   procedure ClassifyRange(Range: TValueRange; Res: TEdit);
  25.   begin
  26.      case Range of
  27.        vrNone: begin Res.Text := '-none-'; Res.Color := clDefault end;
  28.        vrLow: begin Res.Text := 'Low'; Res.Color := $00D9FFCC end;
  29.        vrMedium: begin Res.Text := 'Medium'; Res.Color := $00FFC8C8 end;
  30.        vrHigh: begin Res.Text:= 'High'; Res.Color := $00B9B9FF end;
  31.        vvH: begin Res.Text:= 'Very High'; Res.Color := $00B9B9FF end;
  32.      end;
  33.   end;
  34.  
  35. begin
  36.   // calculate event
  37.   ClassifyRange(InRange(N_Lab,N_Low,N_High,Nvery),N_Res);
  38.   ClassifyRange(InRange(P_Lab,P_Low,P_High,Pvery),P_Res);
  39.   ClassifyRange(InRange(K_Lab,K_Low,K_High,Kvery),K_Res);
Title: Re: case of
Post by: Roland57 on March 09, 2021, 03:09:50 pm
@winni, I've already seen you regret about the lack of sets in FPC more than 256 elements several times.
Are you only interested in the built-in set, or is a home-made one suitable?

Hello! For me, if you have a code to share, I would take it.  :)

Regards.

Roland
Title: Re: case of
Post by: avk on March 09, 2021, 04:05:27 pm
This set(TGSet (https://github.com/avk959/LGenerics/blob/23b33120e76cbb2c5bf9c18c5d41cc0156b37139/lgenerics/lgutils.pas#L1009)) is part of a fairly large unit within the package, but the good news is that this unit is self-sufficient and the TGSet itself depends on the minimum set of functionality of this unit. Thus, it is easy to make TGSet self-contained and the license does not prevent you from doing this.

UPD:  if you have any problems, let me know.
Title: Re: case of
Post by: Roland57 on March 09, 2021, 09:07:23 pm
This set(TGSet (https://github.com/avk959/LGenerics/blob/23b33120e76cbb2c5bf9c18c5d41cc0156b37139/lgenerics/lgutils.pas#L1009)) is part of a fairly large unit within the package, but the good news is that this unit is self-sufficient and the TGSet itself depends on the minimum set of functionality of this unit. Thus, it is easy to make TGSet self-contained and the license does not prevent you from doing this.

Looks very interesting, thank you. I will study it.
Title: Re: case of
Post by: flori on March 10, 2021, 01:38:01 pm
Hi Roland
I attached small app.
I declarate := InRange function and ClassifyRange procedure
-
ClassifyRange(InRange(i, j, k);
Title: Re: case of
Post by: Roland57 on March 10, 2021, 01:51:34 pm
Hi Roland
I attached small app.

Hi! Thank you.
Title: Re: case of
Post by: flori on March 10, 2021, 03:31:49 pm
Just work :)
Try it: for example
LIMITS:
low:20
medium:40
high:60
RESULTS:
N%: 25
CLASSIFICATION
Result: low
TinyPortal © 2005-2018