Recent

Author Topic: Alternative set of string-to-int conversion routines  (Read 26340 times)

Bart

  • Hero Member
  • *****
  • Posts: 5265
    • Bart en Mariska's Webstek
Re: Alternative set of string-to-int conversion routines
« Reply #45 on: January 24, 2022, 11:43:21 pm »
Any illegal string will return 0?
You can have multiple '-'?
'1 2 3' converts to 10203?
'--1' converts to -1
'-1-1-1' converts to -10101
'999999999999999999999999999999999999999999999999999999' gives Aritmetic Overflow.
'000000000000000000000' gives Range Check Error (accessing p[21]).

But yes, it's faster than Val().

This one is also fater than Val():
Code: Pascal  [Select][+][-]
  1. function BartsVal(const S: String): Int64; inline;
  2. begin
  3.   Result := 42;
  4. end;

It's only slightly less accurate than yours, and it will never raise an exception.
And it's the answer to life, the universe and everything.

Bart

Seenkao

  • Hero Member
  • *****
  • Posts: 544
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #46 on: January 25, 2022, 02:13:19 am »
This one is also fater than Val():
Code: Pascal  [Select][+][-]
  1. function BartsVal(const S: String): Int64; inline;
  2. begin
  3.   Result := 42;
  4. end;
Вот оно, идеальное решение!!! :D Этот метод я не смогу ни как ускорить. :(
Eng:
Here it is, the perfect solution! :D I can't speed up this method. :(
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Alternative set of string-to-int conversion routines
« Reply #47 on: January 25, 2022, 09:12:48 am »
IIRC at the time when FPC-3.2.0 was not yet released, this method was the only possible one and attempts to declare a generic type in the implementation section were unconditionally suppressed by the compiler.

You could always declare generic types in the implementation section, so I don't know what problems exactly you remember.

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #48 on: January 25, 2022, 10:34:33 am »
It seems there is no more problem (at least so far :)), thank you.

zamtmn

  • Hero Member
  • *****
  • Posts: 593
Re: Alternative set of string-to-int conversion routines
« Reply #49 on: January 25, 2022, 11:18:13 am »
PascalDragon
I think it means this
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode objfpc}{$H+}
  3. interface
  4.  
  5. generic procedure GTest<T>(aArg:T);
  6.  
  7. implementation
  8.  
  9. generic procedure GImpl<T>(aArg:T);
  10. begin
  11.   writeln(aArg);
  12. end;
  13.  
  14. generic procedure GTest<T>(aArg:T);
  15. begin
  16.   specialize GImpl<T>(aArg);
  17. end;
  18.  
  19. end.
If there are concrete issues with debugging then we need a reproducible example no matter the issue, cause, yes, such things should be fixed, no matter if it's about stepping through generic code correctly or not accidentally entering generic code when one doesn't want it as MarkMLI hinted at.
It looks like it's a bug lazarus https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/39584
Could you comment on which way to dig here https://gitlab.com/freepascal.org/fpc/source/-/issues/39387

zamtmn

  • Hero Member
  • *****
  • Posts: 593
Re: Alternative set of string-to-int conversion routines
« Reply #50 on: January 25, 2022, 01:18:38 pm »
Why? You only need place
Code: Pascal  [Select][+][-]
  1. generic procedure GImpl<T>(aArg:T);
to interface section, and everything works. I'm not saying it's a compiler error, this is just an illustration of how I understood avk
As per Thaddy's remarks, tried to somehow reduce code duplication.
Generic functions need to be declared in the interface part of the unit, and since they are helpers, this is not very good.
Includes are also not suitable, because I want everything to stay in one unit.
As a result, as an experiment, I settled on macros. The code looks unreadable, of course, but it seems that it would not be much better with includes.

Thaddy

  • Hero Member
  • *****
  • Posts: 14157
  • Probably until I exterminate Putin.
Re: Alternative set of string-to-int conversion routines
« Reply #51 on: January 25, 2022, 01:22:26 pm »
That is simply not needed.
Specialize a type, not a var.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Alternative set of string-to-int conversion routines
« Reply #52 on: January 25, 2022, 01:33:30 pm »
PascalDragon
I think it means this
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode objfpc}{$H+}
  3. interface
  4.  
  5. generic procedure GTest<T>(aArg:T);
  6.  
  7. implementation
  8.  
  9. generic procedure GImpl<T>(aArg:T);
  10. begin
  11.   writeln(aArg);
  12. end;
  13.  
  14. generic procedure GTest<T>(aArg:T);
  15. begin
  16.   specialize GImpl<T>(aArg);
  17. end;
  18.  
  19. end.

avk had said pre-3.2.0. Pre-3.2.0 generic functions didn't exist at all.

But yes, in the example you mentioned it is indeed the case that GImpl<> needs to be declared in the interface section. This is by design.

Could you comment on which way to dig here https://gitlab.com/freepascal.org/fpc/source/-/issues/39387

No, I can't, because if I knew that, then I'd already be at the fix essentially.

(Edit: fixed quote)
« Last Edit: January 26, 2022, 09:28:56 am by PascalDragon »

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Alternative set of string-to-int conversion routines
« Reply #53 on: January 26, 2022, 12:17:17 am »
Any illegal string will return 0?
You can have multiple '-'?
'1 2 3' converts to 10203?
'--1' converts to -1
'-1-1-1' converts to -10101
'999999999999999999999999999999999999999999999999999999' gives Aritmetic Overflow.
'000000000000000000000' gives Range Check Error (accessing p[21]).

But yes, it's faster than Val().

This one is also fater than Val():
Code: Pascal  [Select][+][-]
  1. function BartsVal(const S: String): Int64; inline;
  2. begin
  3.   Result := 42;
  4. end;

It's only slightly less accurate than yours, and it will never raise an exception.
And it's the answer to life, the universe and everything.

Bart
I have edited.
I liked a little drink myself when I was 42.
No harm in a drop of John Barleycorn, heck, I live in the country where it was invented .
Have a nice Burn's night.
"And it's the answer to life, the universe and everything."
Very true.



Seenkao

  • Hero Member
  • *****
  • Posts: 544
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #54 on: January 26, 2022, 01:12:23 am »
I have edited.
что изменилось? Вы пробовали тестировать свой код?
Eng:
what changed? Have you tried testing your code?
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Alternative set of string-to-int conversion routines
« Reply #55 on: January 26, 2022, 01:32:13 am »
I have edited.
что изменилось? Вы пробовали тестировать свой код?
Eng:
what changed? Have you tried testing your code?
Yes, tested 32 and 64 bit Windows on Geany ide.
It is better than it was anyway.
Not perfect by any means of course.


Seenkao

  • Hero Member
  • *****
  • Posts: 544
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #56 on: January 26, 2022, 04:45:22 am »
Yes, tested 32 and 64 bit Windows on Geany ide.
It is better than it was anyway.
Not perfect by any means of course.
Вы пробовали вывести отрицательные числа? Числа, пред которыми пробел?
Eng: Have you tried displaying negative numbers? Numbers preceded by a space?

Look at here - the solution has already been provided and it works a little faster. Quite a bit faster than yours.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Alternative set of string-to-int conversion routines
« Reply #57 on: January 26, 2022, 10:40:00 am »
Yes, tested 32 and 64 bit Windows on Geany ide.
It is better than it was anyway.
Not perfect by any means of course.
Вы пробовали вывести отрицательные числа? Числа, пред которыми пробел?
Eng: Have you tried displaying negative numbers? Numbers preceded by a space?

Look at here - the solution has already been provided and it works a little faster. Quite a bit faster than yours.
Hi Seenkao
My example uses -ve number preceded by a space
(' -998880776665550')
I cannot run project files here on Geany, but I compiled your unit and used
sc_StrToInt64(number,res);
in my code instead of val.
If I set a space in front(as in my example) your function gives 0.
Maybe the solution has already been provided as you say, but surely a little input from members does no harm.
And yes, your library function is faster for int64 for strings >5 characters, and a little slower for smaller strings.
Thank you for the unit.
I will try out some code for floats, maybe later.








Thaddy

  • Hero Member
  • *****
  • Posts: 14157
  • Probably until I exterminate Putin.
Re: Alternative set of string-to-int conversion routines
« Reply #58 on: January 26, 2022, 03:00:39 pm »
I cannot run project files here on Geany, but I compiled your unit and used
Edit the geany configuration file. filetype_extensions.conf
You may also want to add the missing keywords. That is another conf file that I forgot, but I will look it up.
You may also want to edit the templates, add a unit.pas etc, and remove the licence if so required.

There are many more options to let geany play nice with Pascal sources.
I am thinking about a wiki entry, since I tend to use geany over fp for simple fpc code.
« Last Edit: January 26, 2022, 03:24:18 pm by Thaddy »
Specialize a type, not a var.

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #59 on: January 26, 2022, 03:46:04 pm »
As an experiment, I added a couple of functions(TryDecimals2Int()) that only accept strings in decimal notation using an idea I saw on the forum.

Some quick and dirty benchmark:
Code: Pascal  [Select][+][-]
  1. program bench2;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4.  
  5. uses
  6.   SysUtils, DateUtils, StrUtils, Str2IntAlter;
  7.  
  8. var
  9.   a: TStringArray = nil;
  10.   Trash: TStringArray = (
  11.     ' --', ' ++', ' +-',' --0', ' ++0', ' +-0',' -0-1', ' +0--1', ' 0-1-1',
  12.     '9223372036854775808', '-9223372036854775809');
  13.  
  14. function NextInt: string;
  15. begin
  16.   case Random(4) of
  17.     0: Result := '  '#9'-' + Random(High(Int64)).ToString;
  18.     1: Result := '  '#9'+' + Random(High(Int64)).ToString;
  19.     2: Result := '  '#9'-' + Random(Int64(High(Dword))).ToString;
  20.   else
  21.     Result := '  '#9'+' + Random(Int64(High(Dword))).ToString;
  22.   end;
  23. end;
  24.  
  25. procedure GenTestData;
  26. var
  27.   I: Integer;
  28. const
  29.   TestSize = 1000;
  30. begin
  31.   SetLength(a, TestSize);
  32.   for I := 0 to High(a) do
  33.     a[I] := NextInt;
  34. end;
  35.  
  36. procedure RunVal;
  37. var
  38.   I, J, r, c: Integer;
  39.   Start: TTime;
  40.   v, Score: Int64;
  41. begin
  42.   for I := 0 to High(Trash) do
  43.     begin
  44.       Val(Trash[I], v, c);
  45.       if c = 0 then
  46.         begin
  47.           WriteLn('Val() accepts trash');
  48.           exit;
  49.         end;
  50.     end;
  51.   r := 0;
  52.   Start := Time;
  53.   for J := 1 to 30000 do
  54.     for I := 0 to High(a) do
  55.       begin
  56.         Val(a[I], v, c);
  57.         Inc(r, Ord(c <> 0));
  58.       end;
  59.   Score := MillisecondsBetween(Time, Start);
  60.   WriteLn('Val(), score:           ', Score);
  61.   WriteLn('rejected:               ', r);
  62. end;
  63.  
  64. procedure RunAlt;
  65. var
  66.   I, J, r: Integer;
  67.   Start: TTime;
  68.   v, Score: Int64;
  69. begin
  70.   for I := 0 to High(Trash) do
  71.     if TryChars2Int(Trash[I][1..Length(Trash[I])], v) then
  72.       begin
  73.         WriteLn('TryChars2Int accepts trash');
  74.         exit;
  75.       end;
  76.   r := 0;
  77.   Start := Time;
  78.   for J := 1 to 30000 do
  79.     for I := 0 to High(a) do
  80.       if not TryChars2Int(a[I][1..Length(a[I])], v) then
  81.         Inc(r);
  82.   Score := MillisecondsBetween(Time, Start);
  83.   WriteLn('TryChars2Int, score:    ', Score);
  84.   WriteLn('rejected:               ', r);
  85. end;
  86.  
  87. procedure RunAltDec;
  88. var
  89.   I, J, r: Integer;
  90.   Start: TTime;
  91.   v, Score: Int64;
  92. begin
  93. for I := 0 to High(Trash) do
  94.   if TryDecimals2Int(Trash[I][1..Length(Trash[I])], v) then
  95.     begin
  96.       WriteLn('TryDecimals2Int accepts trash');
  97.       exit;
  98.     end;
  99.   r := 0;
  100.   Start := Time;
  101.   for J := 1 to 30000 do
  102.     for I := 0 to High(a) do
  103.       if not TryDecimals2Int(a[I][1..Length(a[I])], v) then
  104.         Inc(r);
  105.   Score := MillisecondsBetween(Time, Start);
  106.   WriteLn('TryDecimals2Int, score: ', Score);
  107.   WriteLn('rejected:               ', r);
  108. end;
  109.  
  110. begin
  111.   Randomize;
  112.   GenTestData;
  113.  
  114.   RunVal;
  115.   WriteLn;
  116.   RunAlt;
  117.   WriteLn;
  118.   RunAltDec;
  119.   WriteLn;
  120.  
  121.   WriteLn('Press any key to exit...');
  122.   ReadLn;
  123. end.
  124.  

output x64:
Code: Text  [Select][+][-]
  1. Val(), score:           2445
  2. rejected:               0
  3.  
  4. TryChars2Int, score:    923
  5. rejected:               0
  6.  
  7. TryDecimals2Int, score: 770
  8. rejected:               0
  9.  
  10. Press any key to exit...
  11.  

output x32:
Code: Text  [Select][+][-]
  1. Val(), score:           4598
  2. rejected:               0
  3.  
  4. TryChars2Int, score:    1891
  5. rejected:               0
  6.  
  7. TryDecimals2Int, score: 1178
  8. rejected:               0
  9.  
  10. Press any key to exit...
  11.  

I would like to remind that in this thread we are talking about functions to replace Val(), and therefore these should parse strings according to the same rules as Val().

 

TinyPortal © 2005-2018