### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

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

#### Bart

• Hero Member
• Posts: 4690
##### 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

• Sr. Member
• Posts: 407
##### 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;
Вот оно, идеальное решение!!! Этот метод я не смогу ни как ускорить.
Eng:
Here it is, the perfect solution! I can't speed up this method.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.
Работаю над ZenGL.
Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL.

#### PascalDragon

• Hero Member
• Posts: 4027
• 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: 588
##### 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

• Sr. Member
• Posts: 481
##### 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

• Sr. Member
• Posts: 481
##### 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.

• Hero Member
• Posts: 11543
##### Re: Alternative set of string-to-int conversion routines
« Reply #51 on: January 25, 2022, 01:22:26 pm »
That is simply not needed.
Путин преступник. Россияне дезинформированы.

#### PascalDragon

• Hero Member
• Posts: 4027
• 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: 257
##### 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

• Sr. Member
• Posts: 407
##### 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: Стремлюсь к созданию минимальных и достаточно быстрых приложений.
Работаю над ZenGL.
Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL.

#### BobDog

• Sr. Member
• Posts: 257
##### 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

• Sr. Member
• Posts: 407
##### 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: Стремлюсь к созданию минимальных и достаточно быстрых приложений.
Работаю над ZenGL.
Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL.

#### BobDog

• Sr. Member
• Posts: 257
##### 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.

• Hero Member
• Posts: 11543
##### 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 »
Путин преступник. Россияне дезинформированы.

#### avk

• Hero Member
• Posts: 588
##### 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...');
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().