Recent

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

Seenkao

  • Hero Member
  • *****
  • Posts: 545
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #60 on: January 26, 2022, 06:43:45 pm »
BobDog, на самом деле это не критично. Не такая большая разница, чтоб обращать на разницу в исполнении.
Да, функции предоставленные мной проверяют числа в чистом виде, без пробелов и прочего (исключая знак минус), всё это можно проверить перед функцией и убрать по надобности. Потому и выдало ноль, потому что встретился пробел.
Google translate:
BobDog, actually it is not critical. Not such a big difference to pay attention to the difference in performance.
Yes, the functions provided by me check numbers in their pure form, without spaces and other things (excluding the minus sign), all this can be checked before the function and removed as needed. That's why it gave out zero, because there was a gap.

avk, я не думал, что этот метод сильно ускорит работу с числами. Я ошибался! Увеличение примерно в 1.5 раза. ))) Но только для длинных чисел.
Google translate:
avk, I did not think that this method would greatly speed up the work with numbers. I was wrong! An increase of about 1.5 times. ))) But only for long numbers.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

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

Seenkao

  • Hero Member
  • *****
  • Posts: 545
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #61 on: January 27, 2022, 09:30:40 am »
avk, я не думал, что этот метод сильно ускорит работу с числами. Я ошибался! Увеличение примерно в 1.5 раза. ))) Но только для длинных чисел.
Google translate:
avk, I did not think that this method would greatly speed up the work with numbers. I was wrong! An increase of about 1.5 times. ))) But only for long numbers.
Досадно, но я был прав изначально... как только мы начинаем работать с настоящими строками, а не массивом из Pchar сразу же всё теряется.
При необходимости можно полностью уйти от использования строк и тогда скорость может в два раза возрастёт. Вроде как пользовательские процедуры должны быть, а не для собственного использования. Хотя это на ваше усмотрение.
google translate:
It's a shame, but I was right initially... as soon as we start working with real strings, and not an array from Pchar, everything is immediately lost.
If necessary, you can completely avoid using strings and then the speed can double. Like as the user procedures should be, instead of for own use. Although this is up to you.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

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

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #62 on: January 28, 2022, 10:20:12 am »
Added more overloaded functions for converting strings in decimal notation to integers.

@Seenkao, could you clarify what you are talking about?

Thaddy

  • Hero Member
  • *****
  • Posts: 14160
  • Probably until I exterminate Putin.
Re: Alternative set of string-to-int conversion routines
« Reply #63 on: January 28, 2022, 01:23:56 pm »
as soon as we start working with real strings, and not an array from Pchar, everything is immediately lost.
If necessary, you can completely avoid using strings and then the speed can double.
On the contrary: Pascal strings are more flexible and faster than PChars. That is because strlen (slow, O(n)) to determine length for a pchar vs reading the size of the string at once in Pascal strings (Fast, O(1)). Also PChars can not contain embedded zero's, you would need a char array for that and with a known length. Pascal strings can contain embedded zero's. Using PChars mixed with Pascal strings can lead to strange results, as I already demonstrated.
« Last Edit: January 28, 2022, 01:51:53 pm by Thaddy »
Specialize a type, not a var.

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #64 on: January 30, 2022, 06:57:20 am »
Added some overloads to support unicodestring.
A quick and dirty benchmark against Val() on my machine looks like this:
Code: Text  [Select][+][-]
  1. SInt32:
  2. Val(), score:        3559
  3. rejected:            0
  4. TryChars2Int, score: 780
  5. rejected:            0
  6.  
  7. SInt64:
  8. Val(), score:        4820
  9. rejected:            0
  10. TryChars2Int, score: 1232
  11. rejected:            0
  12.  
  13. UInt32:
  14. Val(), score:        5195
  15. rejected:            0
  16. TryChars2Int, score: 811
  17. rejected:            0
  18.  
  19. UInt64:
  20. Val(), score:        8549
  21. rejected:            0
  22. TryChars2Int, score: 1248
  23. rejected:            0
  24.  

zamtmn

  • Hero Member
  • *****
  • Posts: 593
Re: Alternative set of string-to-int conversion routines
« Reply #65 on: January 30, 2022, 06:59:42 am »
Thanks!
Please add unicode version to bench (TryChars2Int(widechars) vs Val(unicodestring))
« Last Edit: January 30, 2022, 07:03:49 am by zamtmn »

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #66 on: January 30, 2022, 07:19:05 am »
Located in the folder bench_uni, this is its output.

Thaddy

  • Hero Member
  • *****
  • Posts: 14160
  • Probably until I exterminate Putin.
Re: Alternative set of string-to-int conversion routines
« Reply #67 on: January 30, 2022, 10:24:58 am »
Works well, and tnx to include proper tests!
Specialize a type, not a var.

Seenkao

  • Hero Member
  • *****
  • Posts: 545
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #68 on: January 30, 2022, 03:59:51 pm »
@Seenkao, could you clarify what you are talking about?
О том, что пользователь будет использовать StrToInt('-758343');, а не StrToInt('-758343'[1..length('-758343')]. Я поздравляю вас, вы добились скорости. Но вы потеряли в удобстве использования. А когда возвращаем к обычному представлению String вся ваша скорость теряется.
google translate:
That the user will use StrToInt('-758343'); rather than StrToInt('-758343'[1..length('-758343')] I congratulate you, you have achieved speed, but you have lost in usability, and when we return to the usual String representation, all your speed is lost.

On the contrary: Pascal strings are more flexible and faster than PChars. That is because strlen (slow, O(n)) to determine length for a pchar vs reading the size of the string at once in Pascal strings (Fast, O(1)). Also PChars can not contain embedded zero's, you would need a char array for that and with a known length. Pascal strings can contain embedded zero's. Using PChars mixed with Pascal strings can lead to strange results, as I already demonstrated.
Уж извиняюсь, взял код из того что я сделал: fast_StrToInt
Eng: Sorry, I took the code from what I did: fast_StrToInt
Code: Pascal  [Select][+][-]
  1. function geStrToInt(const Str: String; out Value: maxIntVal; Size: LongWord = isInteger): Boolean;
  2. var
  3.   lenStr, i: maxUIntVal;
  4.   m, n, z: maxUIntVal;
  5.   useParametr: PgeUseParametr;
  6.   IntMinus: Boolean;
  7.   correct: maxUIntVal = 0;
  8. label
  9.   jmpEndStr, loopZero;
  10. begin
  11.   {$push}
  12.   {$Q-}{$R-}
  13.   Result := False;
  14.   Value := 0;
  15.   if Size > maxSize then
  16.     Exit;
  17.   IntMinus := False;
  18.   lenStr := Length(Str);
  19.   if lenStr = 0 then
  20.     exit;
  21.   i := 1;
  22.   m := Byte(Str[i]);
  23.  
  24.   if (lenStr = 1) and (m = 48) then
  25.   begin
  26.     Result := True;
  27.     exit;
  28.   end;
  29.   if m = 45 then
  30.   begin
  31.     if lenStr = 1 then
  32.       exit;
  33.     IntMinus := True;
  34.     inc(i);
  35.     m := Byte(Str[2]);
  36.   end;
  37.  
  38. loopZero:
  39.   if m = 48 then
  40.   begin
  41.     inc(i);
  42.     inc(correct);
  43.     m := Byte(Str[i]);
  44.     goto loopZero;
  45.   end;
  46.  
  47.   inc(i);
  48.   m := m - 48;
  49.   if m > 9 then
  50.     exit;
  51.  
  52.   useParametr := @allIntParametr[Size];
  53.   if i > lenStr then
  54.   begin
  55.     z := 0;
  56.     goto jmpEndStr;
  57.   end;
  58.   if (lenStr - correct) > useParametr^.maxLen then
  59.     Exit;
  60.   while i < lenStr do
  61.   begin
  62.     n := (Byte(Str[i]) - 48);
  63.     if n > 9 then
  64.       Exit;
  65.     m := m * 10 + n;
  66.     inc(i);
  67.   end;
  68.  
  69.   if m > useParametr^.maxNumDiv10 then
  70.     exit;
  71.   m := m * 10;
  72.   z := Byte(Str[i]) - 48;
  73.   if z > 9 then
  74.     exit;
  75.  
  76. jmpEndStr:
  77.   if IntMinus then
  78.     n := useParametr^.maxNumeric + 1 - m
  79.   else
  80.     n := useParametr^.maxNumeric - m;
  81.   if z > n then
  82.     exit;
  83.  
  84.   if IntMinus then
  85.     Value := - m - z
  86.   else
  87.     Value := m + z;
  88.   Result := true;
  89.   {$pop}
  90. end;
Переделал:
Remade:
Code: Pascal  [Select][+][-]
  1. function geStrToInt(const Str: array of char; out Value: maxIntVal; Size: LongWord = isInteger): Boolean;
  2. var
  3.   lenStr, i: maxUIntVal;
  4.   m, n, z: maxUIntVal;
  5.   useParametr: PgeUseParametr;
  6.   IntMinus: Boolean = false;
  7.   correct: maxUIntVal = 0;
  8.   v: LongWord;
  9.   pv: PByte;
  10. label
  11.   jmpEndStr, loopZero;
  12. begin
  13.   {$push}
  14.   {$Q-}{$R-}
  15.   Result := False;
  16.   Value := 0;
  17.   if Size > maxSize then
  18.     Exit;
  19.   lenStr := Length(Str);
  20.   if lenStr = 0 then
  21.     exit;
  22.   i := 0;
  23.   m := Byte(Str[i]);
  24.   if (lenStr = 1) and (m = 48) then
  25.   begin
  26.     Result := True;
  27.     exit;
  28.   end;
  29.   if m = 45 then
  30.   begin
  31.     if lenStr = 1 then
  32.       exit;
  33.     IntMinus := True;
  34.     inc(i);
  35.     m := Byte(Str[2]);
  36.   end;
  37. loopZero:
  38.   if m = 48 then
  39.   begin
  40.     inc(i);
  41.     inc(correct);
  42.     m := Byte(Str[i]);
  43.     goto loopZero;
  44.   end;  
  45.   inc(i);
  46.   m := m - 48;
  47.   if m > 9 then
  48.     exit;
  49.   useParametr := @allIntParametr[Size];
  50.   if i > lenStr - 1 then
  51.   begin
  52.     z := 0;
  53.     goto jmpEndStr;
  54.   end;
  55.  
  56.   if (lenStr - correct) > useParametr^.maxLen then
  57.     Exit;
  58.   dec(lenStr);
  59.   while i < lenStr do
  60.   begin
  61.     n := (Byte(Str[i]) - 48);
  62.     if n > 9 then
  63.       Exit;
  64.     m := m * 10 + n;
  65.     inc(i);
  66.   end;
  67.   if m > useParametr^.maxNumDiv10 then
  68.     exit;
  69.   m := m * 10;
  70.   z := Byte(Str[i]) - 48;
  71.   if z > 9 then
  72.     exit;
  73.  
  74. jmpEndStr:
  75.   if IntMinus then
  76.     n := useParametr^.maxNumeric + 1 - m
  77.   else
  78.     n := useParametr^.maxNumeric - m;
  79.   if z > n then
  80.     exit;
  81.  
  82.   if IntMinus then
  83.     Value := - m - z
  84.   else
  85.     Value := m + z;
  86.   Result := true;
  87.   {$pop}
  88. end;
И при тестах в первом варианте (работа со String) function geStrToInt(const Str: String; out Value: maxIntVal; Size: LongWord = isInteger): Boolean; я получаю меньшую скорость обработки, чем во втором (работа с массивом PChar) function geStrToInt(const Str: array of char; out Value: maxIntVal; Size: LongWord = isInteger): Boolean;. Вторая функция работает в два с лишним раза быстрее!!!
Не хотите прокомментировать что происходит? И почему вы утверждаете обратное?
Google translate:
And when testing in the first option (working with String) function geStrToInt(const Str: String; out Value: maxIntVal; Size: LongWord = isInteger): Boolean; I get a lower processing speed than in the second ( working with a PChar array) function geStrToInt(const Str: array of char; out Value: maxIntVal; Size: LongWord = isInteger): Boolean;. The second function works more than twice as fast!!!
Would you like to comment on what's going on? And why are you saying otherwise?

avk, по сути я приложил пример (и не я один), в котором простые вещи обходят слишком замудрёные. Эту функцию function geStrToInt(const Str: array of char; out Value: maxIntVal; Size: LongWord = isInteger): Boolean; сложно обойти по скорости, там уже практически нечего ускорять. Даже используя ваш метод с QWord и DWord.
Google translate:
avk, in fact, I attached an example (and I'm not the only one) in which simple things bypass too complicated ones. This function function geStrToInt(const Str: array of char; out Value: maxIntVal; Size: LongWord = isInteger): Boolean; is hard to get around in terms of speed, there is practically nothing to speed up. Even using your method with QWord and DWord.

My test:
Quote
StrToInt standard     7.8757494776072852E+000
StrToInt made by me  1.5074538423153692E+000
StrToInt made by avk  2.0989100899762976E+000
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

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

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #69 on: January 30, 2022, 04:56:22 pm »
First of all, I would like to remind you that this section of the forum is called "Third Party announcements", and this topic discusses a specific library.
If you want to discuss something different, it is better to create a new thread for this.
As for Str2IntAlter, it don't seem to be restricting the user in any way in choosing a particular version of the function.
One could try to compare their performance(adding function from fast_StrToInt at the same time), for example:
Code: Pascal  [Select][+][-]
  1. program bench;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4.  
  5. uses
  6.   SysUtils, DateUtils, StrUtils, Str2IntAlter, ge_external_Utils;
  7.  
  8. function NextRandomQWord: QWord;
  9. begin
  10.   Result := QWord(Random(Int64($100000000))) shl 32 or QWord(Random(Int64($100000000)));
  11. end;
  12.  
  13. function NextUInt64: string;
  14. begin
  15.   case Random(4) of
  16.     0: Result := ' '#9'+%' + NextRandomQWord.ToBinString;
  17.     1: Result := ' '#9'+&' + OctStr(NextRandomQWord, 22);
  18.     2: Result := ' '#9'+' + NextRandomQWord.ToString;
  19.   else
  20.     Result := ' '#9'+$' + NextRandomQWord.ToHexString;
  21.   end;
  22. end;
  23.  
  24. var
  25.   a: TStringArray = nil;
  26.  
  27. procedure GenTestData;
  28. var
  29.   I: Integer;
  30. const
  31.   TestSize = 1000;
  32. begin
  33.   SetLength(a, TestSize);
  34.   for I := 0 to High(a) do
  35.     a[I] := NextUInt64;
  36. end;
  37.  
  38. procedure RunChars;
  39. var
  40.   I, J, r: Integer;
  41.   Start: TTime;
  42.   Score: Int64;
  43.   v: QWord;
  44. begin
  45.   r := 0;
  46.   Start := Time;
  47.   for J := 1 to 30000 do
  48.     for I := 0 to High(a) do
  49.       if not TryChars2Int(a[I][1..Length(a[I])], v) then
  50.         Inc(r);
  51.   Score := MillisecondsBetween(Time, Start);
  52.   WriteLn('TryChars2Int, score:  ', Score);
  53.   WriteLn('rejected:             ', r);
  54. end;
  55.  
  56. procedure RunStr;
  57. var
  58.   I, J, r: Integer;
  59.   Start: TTime;
  60.   Score: Int64;
  61.   v: QWord;
  62. begin
  63.   r := 0;
  64.   Start := Time;
  65.   for J := 1 to 30000 do
  66.     for I := 0 to High(a) do
  67.       if not TryStr2Int(a[I], v) then
  68.         Inc(r);
  69.   Score := MillisecondsBetween(Time, Start);
  70.   WriteLn('TryStr2Int, score:    ', Score);
  71.   WriteLn('rejected:             ', r);
  72. end;
  73.  
  74. procedure RunSeen;
  75. var
  76.   I, J, r: Integer;
  77.   Start: TTime;
  78.   Score: Int64;
  79.   v: QWord;
  80. begin
  81.   r := 0;
  82.   Start := Time;
  83.   for J := 1 to 30000 do
  84.     for I := 0 to High(a) do
  85.       if not sc_StrToQWord(a[I], v) then
  86.         Inc(r);
  87.   Score := MillisecondsBetween(Time, Start);
  88.   WriteLn('sc_StrToQWord, score: ', Score);
  89.   WriteLn('rejected:             ', r);
  90. end;
  91.  
  92. begin
  93.   Randomize;
  94.   GenTestData;
  95.  
  96.   RunChars;
  97.   WriteLn;
  98.   RunStr;
  99.   WriteLn;
  100.   RunSeen;
  101.   WriteLn;
  102.  
  103.   WriteLn('Press enter to exit...');
  104.   ReadLn;
  105. end.
  106.  

I get such result:
Code: Text  [Select][+][-]
  1. TryChars2Int, score:  1762
  2. rejected:             0
  3.  
  4. TryStr2Int, score:    1740
  5. rejected:             0
  6.  
  7. sc_StrToQWord, score: 130
  8. rejected:             30000000
  9.  
  10. Press enter to exit...
  11.  

So I still don't understand what you mean.
« Last Edit: January 30, 2022, 05:37:34 pm by avk »

Seenkao

  • Hero Member
  • *****
  • Posts: 545
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #70 on: January 30, 2022, 06:36:02 pm »
Code: [Select]
[quote author=avk link=topic=57934.msg432772#msg432772 date=1643558182]
sc_StrToQWord, score: 130
rejected:             30000000
[/quote]
Я изначально не стремился обрабатывать дополнительные символы, кроме ведущих для чисел. Моя библиотека принимает именно числа. А не входящую билеберду. Извиняюсь!
Именно по этой причине, вы видите лишь "ошибки". Если я вам в числа залью буквы, вы так же эти ошибки увидите в своих функциях.
Всю билеберду, можно убрать до вызова. Это не займёт много времени исполнения, а при работе с числами, пользователь как раз обрабатывает символы для чисел. И при правильной программе, не будет ни каких посторонних символов. Кроме ведущих нулей, и выделения системы счисления. Я изначально рассчитывал именно на скорость. Но не думал что настолько получу ускорение.
google translate:
I didn't initially aim to handle additional characters other than leading ones for numbers. My library accepts exactly numbers. And not the incoming billebird. I'm sorry!
It is for this reason that you only see "errors". If I put letters in numbers for you, you will also see these errors in your functions.
All billeberd can be removed before the call. This will not take much execution time, and when working with numbers, the user is just processing the characters for numbers. And with the right program, there will be no extraneous characters. In addition to leading zeros, and the selection of the number system. I originally counted on the speed. But I did not think that I would get such an acceleration.

Quote
So I still don't understand what you mean.
Когда я писал, у вас была выложена только функция function TryDecimals2Int(const a: array of char; out aValue: LongWord): Boolean; без String! Я обрадовался когда увидел, что ваша функция обошла мою по скорости! Но позже, я её переписал для String и вся скорость потерялась на этом этапе.
После этого я переписал свою под массив PChar. И увидел в чём реальное ускорение было. А ускорение было не в функции, а в том, чтоб не использовать String в функции.
Вероятно потому вы и не понимаете о чём я пишу. Функций function TryDecStr2Int(const s: string; out aValue: LongWord): Boolean; у вас тогда ещё не было.
google translate:
When I wrote, you only had function TryDecimals2Int(const a: array of char; out aValue: LongWord): Boolean; without String! I was delighted when I saw that your function bypassed mine in speed! But later, I rewrote it for String and all the speed was lost at this stage.
After that, I rewrote mine under the PChar array. And I saw what the real acceleration was. And the acceleration was not in the function, but in not using String in the function.
That's probably why you don't understand what I'm talking about. Functions function TryDecStr2Int(const s: string; out aValue: LongWord): Boolean; you did not yet have.

Но у меня возникает вопрос, а почему в вашем коде не идёт ускорение при использовании массива PChar? Функция TryChars2Int(a[1..Length(a)], v) работает явно быстрее. На каком моменте в коде начинает проявляться перевод String в массив PChar?
TryChars2Int(a[1..Length(a)], v) работает в два раза быстрее чем TryStr2Int(a, v). Почему в вашем коде это не работает быстрее?
google translate:
But I have a question, why is there no acceleration in your code when using the PChar array? The function TryChars2Int(a[1..Length(a)], v) is clearly faster. At what point in the code does the translation of String into a PChar array begin to appear?
TryChars2Int(a[1..Length(a)], v) is twice as fast as TryStr2Int(a, v) . Why doesn't it work faster in your code?
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

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

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #71 on: January 30, 2022, 07:17:41 pm »
The library that is discussed in the current topic tries to be compatible with Val().
Other options are not interesting.

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Alternative set of string-to-int conversion routines
« Reply #72 on: January 30, 2022, 08:10:10 pm »

Val, of course, also covers float numbers.
Actually fp val is quite fast compared to C.
it is also much faster than freebasic val.

Code: Pascal  [Select][+][-]
  1. uses
  2. sysutils;
  3. function atof(p:pchar):double;cdecl  external 'msvcrt.dll' name 'atof';
  4. function strtod (p:pchar; b :pointer):double cdecl  external 'msvcrt.dll' name 'strtod';
  5. var
  6.  t:int64;
  7.  res:double;
  8.  code:word;
  9.  k,i:longword;
  10.  number: ansistring='  -12345.6789';
  11.  b:^pbyte=nil;
  12.  begin
  13.  
  14. for k:=1 to 5 do
  15. begin
  16. t:=gettickcount64;
  17. for i:=0 to 1000000 do
  18. res:=strtod(pchar(number),b);
  19. writeln(gettickcount64-t,' milliseconds strtod = ',res);
  20.  
  21. t:=gettickcount64;
  22. for i:=0 to 1000000 do
  23.  
  24. val(number,res,code);
  25. writeln(gettickcount64-t,' milliseconds  val =   ',res);
  26.  
  27. t:=gettickcount64;
  28. for i:=0 to 1000000 do
  29. res:=atof(pchar(number));
  30. writeln(gettickcount64-t,' milliseconds   atof = ',res);
  31. writeln;
  32. end;
  33. writeln('Press enter to end . . .');
  34. readln;
  35. end.
  36.  
  37.  


It shouldn't be too hard to include floats in pascal conversions, but searching for the decimal point will slow things down.

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Alternative set of string-to-int conversion routines
« Reply #73 on: January 31, 2022, 07:26:54 am »

Val, of course, also covers float numbers.
...

Does this have anything to do with "set of string-to-int conversion routines"?

Seenkao

  • Hero Member
  • *****
  • Posts: 545
    • New ZenGL.
Re: Alternative set of string-to-int conversion routines
« Reply #74 on: January 31, 2022, 08:21:03 am »
The library that is discussed in the current topic tries to be compatible with Val().
Other options are not interesting.

Val, of course, also covers float numbers.
...

Does this have anything to do with "set of string-to-int conversion routines"?
Мда... сами себе противоречите? )))
И ваши функции не совместимы с Val. Потому что Val - это одна функция, работающая с разнообразным множеством чисел. Ваши функции могут быть лишь совместимы с производными от Val. До тех пор, пока это не станет одной функцией.
Это так, для информации. Успехов!
google translate:
Hmm ... contradict yourself? )))
And your functions are not compatible with Val. Because Val is one function that works with a diverse set of numbers. Your functions can only be compatible with Val derivatives. Until it becomes one function.
This is so, for information. Good luck!
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

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

 

TinyPortal © 2005-2018