Note the following lsiting, and resulting assembly code (i686, Linux):
You might think that the function is very optimized, since it requires only two comparisons and a lookup in table per character checked?
Alas, GPC does a proper call to the real memcpy() function of complete ``v'' array on each call of function DigitValue() !!!
This makes the run twice as slow as when ``v'' array is made global (edited):
----------------------------------------------------- make test arr a=8 116.290u 0.400s 1:59.62 97.5% 0+0k 0+0io 10385pf+0w time a.out arr a=8 114.190u 0.280s 1:58.53 96.5% 0+0k 0+0io 120pf+0w 114.500u 0.210s 2:03.95 92.5% 0+0k 0+0io 120pf+0w 114.650u 0.040s 1:57.13 97.9% 0+0k 0+0io 121pf+0w 114.840u 0.020s 1:57.00 98.1% 0+0k 0+0io 120pf+0w 115.180u 0.040s 2:05.03 92.1% 0+0k 0+0io 120pf+0w 106.200u 1.390s 2:07.25 84.5% 0+0k 0+0io 120pf+0w 111.700u 0.080s 2:04.02 90.1% 0+0k 0+0io 120pf+0w make test arr a=8 glob 65.840u 0.160s 1:07.62 97.6% 0+0k 0+0io 10385pf+0w time a.out arr a=8 glob 63.610u 0.060s 1:06.63 95.5% 0+0k 0+0io 120pf+0w 63.710u 0.030s 1:05.21 97.7% 0+0k 0+0io 120pf+0w 63.620u 0.040s 1:06.02 96.4% 0+0k 0+0io 120pf+0w 63.610u 0.030s 1:05.41 97.2% 0+0k 0+0io 120pf+0w 63.840u 0.000s 1:05.15 97.9% 0+0k 0+0io 120pf+0w 63.980u 0.010s 1:05.29 98.0% 0+0k 0+0io 120pf+0w 64.000u 0.020s 1:05.19 98.2% 0+0k 0+0io 120pf+0w -----------------------------------------------------
Just FYI, making ``v'' array [0..255] of Integer (for aligned access) made it even 10s slower (probably problems with FSB and cache), instead of what is commonly said, and complete code is not a bit faster from this variant:
function DigitValue (Dig: Char): Integer; attribute (inline, const); var d : Integer; attribute (register); begin if (Dig >= '0') and (Dig <= '9' ) then DigitValue := Ord (Dig) - Ord ('0') else if (Dig >= 'a') and (Dig <= 'z') then DigitValue := Ord (Dig) - Ord ('a') + 10 else if (Dig >= 'A') and (Dig <= 'Z') then DigitValue := Ord (Dig) - Ord ('A') + 10 else DigitValue := -1 end;
... even though this code has six branches.
Is it the GNU Pascal problem or the back-end problem?
NOTE: even attribute (const) after initialization of the array didn't help to evade memcpy().
Mirsad
isvalidnumberbase.pas: ---------------------------------------------------------------------------- program isvalidnum (output);
var i, Base: Integer; OK : Boolean;
function IsValidNumberBase2 (s: String; Base: Integer): Boolean; attribute(const); var i, dv : Integer; attribute (register); b : Byte; attribute (register); function DigitValue (Dig: Char): Integer; {attribute (inline, const);} var d : Integer; attribute (register); {$if 0} {$if Low (Char) < 0} {$error "this won't work: negative Char used as index} {$endif} {$endif} v : array [0..255] of ByteInt = ( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 );
begin if (Dig >= '0') and (Dig <= 'z') then DigitValue := v[Ord (Dig)] else DigitValue := -1; end;
begin b := Base; Assert ((b >= 2) and (b <= 36), 'base out of range (2..36)'); i := 1; if s[i] = '-' then Inc (i); for i := i to Length (s) do {$define VERSION1} {$ifdef VERSION1} begin dv := DigitValue (s[i]); if (dv < 0) or (dv >= b) then Return False end; {$else} if not (DigitValue (s[i]) in [0 .. b-1]) then Return False; {$endif} Return True; end;
begin { main } OK := IsValidNumberBase2 ('010101010101101010101', 2) and not IsValidNumberBase2 ('0101010210101101010101', 2) and IsValidNumberBase2 ('0121012210101101010101', 3);
if OK then WriteLn ('OK'); end. -------------------------------------------------------------------------
isvalidnumberbase.s (edited): ------------------------------------------------------------------------- .file "isvalidnumberbase.pas" .local I .comm I,4,4 .local Base .comm Base,4,4 .local Ok .comm Ok,1,1 .section .rodata .LC0: .byte -1 . . . .byte -1 .byte -1 .byte -1 .byte 0 .byte 1 .byte 2 .byte 3 .byte 4 .byte 5 .byte 6 .byte 7 .byte 8 .byte 9 .byte -1 .byte -1 .byte -1 .byte -1 .byte -1 .byte -1 .byte -1 .byte 10 .byte 11 .byte 12 .byte 13 .byte 14 .byte 15 .byte 16 .byte 17 .byte 18 .byte 19 .byte 20 .byte 21 .byte 22 .byte 23 .byte 24 .byte 25 .byte 26 .byte 27 .byte 28 .byte 29 .byte 30 .byte 31 .byte 32 .byte 33 .byte 34 .byte 35 .byte 36 .byte -1 .byte -1 .byte -1 .byte -1 .byte -1 .byte 10 .byte 11 .byte 12 .byte 13 .byte 14 .byte 15 .byte 16 .byte 17 .byte 18 .byte 19 .byte 20 .byte 21 .byte 22 .byte 23 .byte 24 .byte 25 .byte 26 .byte 27 .byte 28 .byte 29 .byte 30 .byte 31 .byte 32 .byte 33 .byte 34 .byte 35 .byte 36 .byte -1 .byte -1 . . . .byte -1 .byte -1 .byte -1 .byte -1 .text .p2align 4,,15 .type Digitvalue.0,@function Digitvalue.0: pushl %ebp movl %esp, %ebp subl $296, %esp movl %ebx, -4(%ebp) leal -280(%ebp), %eax movzbl 8(%ebp), %ebx movl %ecx, -12(%ebp) movl $256, 8(%esp) movl $.LC0, 4(%esp) movl %eax, (%esp) call memcpy cmpb $47, %bl jbe .L4 cmpb $122, %bl ja .L4 movzbl %bl, %eax movsbl -280(%eax,%ebp),%eax .L5: movl -4(%ebp), %ebx movl %ebp, %esp popl %ebp ret .p2align 4,,7 .L4: movl $-1, %eax jmp .L5 .Lfe1: .size Digitvalue.0,.Lfe1-Digitvalue.0 .section .rodata.str1.1,"aMS",@progbits,1 .LC1: .string "base out of range (2..36)" .text .p2align 4,,15 .globl Isvalidnumberbase2 .type Isvalidnumberbase2,@function Isvalidnumberbase2: pushl %ebp movl %esp, %ebp pushl %edi pushl %esi pushl %ebx subl $92, %esp movl 8(%ebp), %edi movzbl 12(%ebp), %eax cmpb $1, %al seta %bl movb %al, -73(%ebp) testb %bl, %bl je .L6 cmpb $36, %al setbe %bl .L6: movl $25, -72(%ebp) leal -64(%ebp), %eax movl $25, 8(%esp) movl $.LC1, 4(%esp) movl %eax, (%esp) call memcpy leal -72(%ebp), %eax movl %eax, 4(%esp) movzbl %bl, %eax movl $1, %ebx movl $25, -68(%ebp) movl %eax, (%esp) call _p_Assert cmpb $45, 8(%edi) je .L18 .L8: movl 4(%edi), %esi cmpl %esi, %ebx jg .L9 movb $0, -74(%ebp) .p2align 4,,15 .L10: cmpb $0, -74(%ebp) je .L12 cmpl %esi, %ebx je .L9 incl %ebx .L12: movb $1, -74(%ebp) leal -24(%ebp), %ecx movzbl 7(%edi,%ebx), %eax movl %eax, (%esp) call Digitvalue.0 movl %eax, %ecx shrl $31, %ecx testb %cl, %cl movl %eax, %edx jne .L17 movzbl -73(%ebp), %eax cmpl %eax, %edx jl .L14 testl %edx, %edx js .L14 movb $1, %cl .L14: testb %cl, %cl je .L10 .L17: xorl %eax, %eax .L1: addl $92, %esp popl %ebx popl %esi popl %edi popl %ebp ret .p2align 4,,7 .L9: movb $1, %al jmp .L1 .L18: movl $2, %ebx jmp .L8 .Lfe2: .size Isvalidnumberbase2,.Lfe2-Isvalidnumberbase2 .section .rodata.str1.1 .LC2: .string "010101010101101010101" .LC5: .string "OK" .LC4: .string "0121012210101101010101" .LC3: .string "0101010210101101010101" .text .p2align 4,,15 .globl pascal_main_program .type pascal_main_program,@function pascal_main_program: pushl %ebp movl %esp, %ebp subl $136, %esp movl $21, 8(%esp) leal -32(%ebp), %eax movl $21, -40(%ebp) movl $.LC2, 4(%esp) movl %eax, (%esp) call memcpy leal -40(%ebp), %eax movl $21, -36(%ebp) movl $2, 4(%esp) movl %eax, (%esp) call Isvalidnumberbase2 testb %al, %al jne .L28 .L21: testb %al, %al jne .L29 .L23: movb %al, Ok testb %al, %al jne .L30 .L19: movl %ebp, %esp popl %ebp ret .p2align 4,,7 .L30: movl $22, 24(%esp) movl $2, 20(%esp) movl $.LC5, 16(%esp) movl $17, 12(%esp) movl $2, 8(%esp) movl $784, 4(%esp) movl $_p_Output, (%esp) call _p_Internal_Write movl _p_InOutRes, %eax testl %eax, %eax je .L19 jmp .L31 .p2align 4,,7 .L29: movl $22, -104(%ebp) leal -96(%ebp), %eax movl $22, 8(%esp) movl $.LC4, 4(%esp) movl %eax, (%esp) call memcpy leal -104(%ebp), %eax movl $22, -100(%ebp) movl $3, 4(%esp) movl %eax, (%esp) call Isvalidnumberbase2 jmp .L23 .p2align 4,,7 .L28: movl $22, -72(%ebp) leal -64(%ebp), %eax movl $22, 8(%esp) movl $.LC3, 4(%esp) movl %eax, (%esp) call memcpy leal -72(%ebp), %eax movl $22, -68(%ebp) movl $2, 4(%esp) movl %eax, (%esp) call Isvalidnumberbase2 testb %al, %al sete %al jmp .L21 .L31: call _p_CheckInOutRes .Lfe3: .size pascal_main_program,.Lfe3-pascal_main_program .data .type ctor_run_condition_14.1,@object .size ctor_run_condition_14.1,1 ctor_run_condition_14.1: .byte 0 .text .p2align 4,,15 .globl init_pascal_main_program .type init_pascal_main_program,@function init_pascal_main_program: cmpb $0, ctor_run_condition_14.1 pushl %ebp movl %esp, %ebp je .L34 popl %ebp ret .p2align 4,,7 .L34: popl %ebp movb $1, ctor_run_condition_14.1 jmp _p_DoInitProc .Lfe4: .size init_pascal_main_program,.Lfe4-init_pascal_main_program .p2align 4,,15 .globl main .type main,@function main: pushl %ebp movl %esp, %ebp subl $24, %esp movl __GPC_RTS_VERSION_20030507__, %eax movl 16(%ebp), %eax andl $-16, %esp movl %eax, 8(%esp) movl 12(%ebp), %eax movl %eax, 4(%esp) movl 8(%ebp), %eax movl %eax, (%esp) call _p_initialize call init_pascal_main_program call pascal_main_program call _p_finalize movl %ebp, %esp xorl %eax, %eax popl %ebp ret .Lfe5: .size main,.Lfe5-main .ident "GCC: (GNU) 3.2.1" -------------------------------------------------------------------------------
Mirsad Todorovac wrote:
You might think that the function is very optimized, since it requires only two comparisons and a lookup in table per character checked?
Alas, GPC does a proper call to the real memcpy() function of complete ``v'' array on each call of function DigitValue() !!!
Normal local variables are (by definition!) created each time the routine is called. To avoid this, give them the `static' attribute (non-standard), or declare them as `const' (non-standard, BP). The latter is obviously preferrable since the array is really constant.
BTW, since you only access the array in the range '0' .. 'z', you only need to declare this part and can omit the lots of `-1' entries. Also, char indices are perfectly alright, so you don't have to use `Ord' here.
Just FYI, making ``v'' array [0..255] of Integer (for aligned access) made it even 10s slower (probably problems with FSB and cache), instead of what is commonly said,
Probably because of the initialization (see above) which takes 4 or 8 times as long then, of course (and which takes most time at all).
and complete code is not a bit faster from this variant:
function DigitValue (Dig: Char): Integer; attribute (inline, const); var d : Integer; attribute (register); begin if (Dig >= '0') and (Dig <= '9' ) then DigitValue := Ord (Dig) - Ord ('0') else if (Dig >= 'a') and (Dig <= 'z') then DigitValue := Ord (Dig) - Ord ('a') + 10 else if (Dig >= 'A') and (Dig <= 'Z') then DigitValue := Ord (Dig) - Ord ('A') + 10 else DigitValue := -1 end;
... even though this code has six branches.
Only 3 branches (the backend optimized better than you think -- unfortunately in this case only with `{$B+}', since Boolean shortcuts require special handling) which makes the array above look rather questionable ...
Frank
Frank Heckenbach wrote:
Mirsad Todorovac wrote:
You might think that the function is very optimized, since it requires only two comparisons and a lookup in table per character checked?
Alas, GPC does a proper call to the real memcpy() function of complete ``v'' array on each call of function DigitValue() !!!
Normal local variables are (by definition!) created each time the routine is called. To avoid this, give them the `static' attribute (non-standard), or declare them as `const' (non-standard, BP). The latter is obviously preferrable since the array is really constant.
BTW, since you only access the array in the range '0' .. 'z', you only need to declare this part and can omit the lots of `-1' entries. Also, char indices are perfectly alright, so you don't have to use `Ord' here.
Just FYI, making ``v'' array [0..255] of Integer (for aligned access) made it even 10s slower (probably problems with FSB and cache), instead of what is commonly said,
Probably because of the initialization (see above) which takes 4 or 8 times as long then, of course (and which takes most time at all).
and complete code is not a bit faster from this variant:
function DigitValue (Dig: Char): Integer; attribute (inline, const); var d : Integer; attribute (register); begin if (Dig >= '0') and (Dig <= '9' ) then DigitValue := Ord (Dig) - Ord ('0') else if (Dig >= 'a') and (Dig <= 'z') then DigitValue := Ord (Dig) - Ord ('a') + 10 else if (Dig >= 'A') and (Dig <= 'Z') then DigitValue := Ord (Dig) - Ord ('A') + 10 else DigitValue := -1 end;
... even though this code has six branches.
Only 3 branches (the backend optimized better than you think -- unfortunately in this case only with `{$B+}', since Boolean shortcuts require special handling) which makes the array above look rather questionable ...
My view:
PROGRAM try(output);
CONST digits = ['0'..'9']; upcase = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; lowcase = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; ordmaxchar = 255; (* not guaranteed immutable *)
(* and so far I am char set independant - EBCDIC is fine *)
TYPE base = 2..36;
VAR digval : ARRAY[char] OF integer; alfamerics : SET OF char;
(* 1--------------1 *)
PROCEDURE initdigval;
VAR c : char;
BEGIN (* initdigval *) alfamerics := digits + upcase + lowcase; FOR c := chr(0) TO chr(ordmaxchar) DO BEGIN digval := -1; IF c IN digits THEN digval := ord(c) - ord('0'); END; digval['a'] := 10; digval['A'] := 10; digval['b'] := 11; digval['B'] := 11; digval['c'] := 12; digval['C'] := 12; (* I'm tired -- you get the idea *) END; (* initdigval *)
(* 1--------------1 *)
(* Now we are forced to get into 'what is a string' * Feel free to adjust to other possibilities * My attitude is that a number can be a substring * and that an invalid char signifies the end of * that substring. So this routine doesn't deserve * existance, the process should extract a number * from a string, and indicate the end of the substr. *) FUNCTION isvalidnumber(VAR s : string; b : base) : boolean;
VAR cv : integer;
BEGIN (* isvalidnumber *) cv := digval[s[1]]; isvalidnumber := (cv < b) AND (cv >= 0); (* this statement may indicate that -1 is a poor choice *) (* Maybe the default should be MAXINT in initdigval *) END; (* isvalidnumber *)
and I won't tire you with further code. However, portability should IMO include proper adaptation to char sets, which the above handles. Simple variants can handle languages with other characters, other casing rules, etc. For number conversion we need not make any such allowances, but we do need to spell things out.
There should be no need for assert statements, with properly restricted subranges, as in the type definition of base above.
Note that the above table can be used in an EBCDIC machine to translate alfamerics to ASCII.
aside: Frank, I am still mulling a reply to your previous note on initialization - I think you misunderstand my attitude.
CBFalconer wrote:
There should be no need for assert statements, with properly restricted subranges, as in the type definition of base above.
I agree to this part (though not to the clumsy initialization and the debates about "what is a string" which is well anwered in EP). But declaring the base of type `2 .. 36' will help avoid any special checks in the routine. (Though GPC doesn't range-check yet, but it will soon, and it's nothing for the routine to worry about.)
Frank
On Sun, 8 Jun 2003, Frank Heckenbach wrote:
Mirsad Todorovac wrote:
You might think that the function is very optimized, since it requires only two comparisons and a lookup in table per character checked?
Alas, GPC does a proper call to the real memcpy() function of complete ``v'' array on each call of function DigitValue() !!!
Normal local variables are (by definition!) created each time the routine is called. To avoid this, give them the `static' attribute (non-standard), or declare them as `const' (non-standard, BP). The latter is obviously preferrable since the array is really constant.
``Attribute (static)'' pushes copying out of function, but ``attribute (const)'' is still copying the array in each function call!, giving (i686):
Digitvalue.0: pushl %ebp movl %esp, %ebp subl $296, %esp movl %ebx, -4(%ebp) leal -280(%ebp), %edx movzbl 8(%ebp), %ebx movl %edx, (%esp) movl %ecx, -12(%ebp) movl $256, 8(%esp) movl $.LC0, 4(%esp) call memcpy ;-( movzbl %bl, %edx movl -4(%ebp), %ebx movsbl -280(%edx,%ebp),%eax movl %ebp, %esp popl %ebp ret
instead of ``attribute (static)'' version:
Digitvalue.0: pushl %ebp movl %esp, %ebp subl $4, %esp movzbl 8(%ebp), %edx movsbl V.1(%edx),%eax movl %ebp, %esp popl %ebp ret
Besides this, since array [0..255] can be and probably should be properly aligned on 32-bit boundary, compiler could call (considerably faster) mempcpy_by4, which copies 32-bit-wise, and/or could (at least with -O3) inline the code.
(IMHO the former especially since the compiler knows the length of the array at compile time.)
BTW, since you only access the array in the range '0' .. 'z', you only need to declare this part and can omit the lots of `-1' entries. Also, char indices are perfectly alright, so you don't have to use `Ord' here.
Thanks for reminding me. I chose to remove that if a in ['0'..'z'] ...
Just FYI, making ``v'' array [0..255] of Integer (for aligned access) made it even 10s slower (probably problems with FSB and cache), instead of what is commonly said,
Probably because of the initialization (see above) which takes 4 or 8 times as long then, of course (and which takes most time at all).
No, I am comparing static versions of array [0..255] of ByteInt and array [0..255] of MedInt ... the latter is still 10% slower. IMHO this is because former occupies less space in cache, obviously, which is on 1.1 GHZ/133 MHz FSB machine probably quite relevant.
and complete code is not a bit faster from this variant:
function DigitValue (Dig: Char): Integer; attribute (inline, const); var d : Integer; attribute (register); begin if (Dig >= '0') and (Dig <= '9' ) then DigitValue := Ord (Dig) - Ord ('0') else if (Dig >= 'a') and (Dig <= 'z') then DigitValue := Ord (Dig) - Ord ('a') + 10 else if (Dig >= 'A') and (Dig <= 'Z') then DigitValue := Ord (Dig) - Ord ('A') + 10 else DigitValue := -1 end;
... even though this code has six branches.
Only 3 branches (the backend optimized better than you think -- unfortunately in this case only with `{$B+}', since Boolean shortcuts require special handling) which makes the array above look rather questionable ...
Not completelly ;-)
Here are timings:
mtm017 arr byteint 252.01 mtm017 arr medint 279.63 (+10.96%) mtm017 iteite 286.36 (+13.63%) mtm017 iteite + and_then 285.77 (+13.40%)
(And_then is an equivalent of {B+}, isn't it?)
So, the answer is: using array still *is* faster ;-)
Besides, it is a small function and it's fit for inlining, and
begin Digitvalue := v[ Dig ]; end;
inlines better than all that
if ... then ... else if ... then ... else if ... then ...;
stuff, IMHO. So, we save both time and space :-)
(Once we made the array constant to evade copying on each call, of course.)
Mirsad
Mirsad Todorovac wrote:
Normal local variables are (by definition!) created each time the routine is called. To avoid this, give them the `static' attribute (non-standard), or declare them as `const' (non-standard, BP). The latter is obviously preferrable since the array is really constant.
``Attribute (static)'' pushes copying out of function, but ``attribute (const)'' is still copying the array in each function call!,
`attribute (const)' is not the same as declaring a constant.
Besides this, since array [0..255] can be and probably should be properly aligned on 32-bit boundary,
Arrays are generally aligned the same as their elements.
(And_then is an equivalent of {B+}, isn't it?)
No, it's just the opposite.
stuff, IMHO. So, we save both time and space :-)
How often do you call the function (in the same unit), so it would save the space of that array?
Frank
On Mon, 9 Jun 2003, Frank Heckenbach wrote:
Mirsad Todorovac wrote:
Normal local variables are (by definition!) created each time the routine is called. To avoid this, give them the `static' attribute (non-standard), or declare them as `const' (non-standard, BP). The latter is obviously preferrable since the array is really constant.
``Attribute (static)'' pushes copying out of function, but ``attribute (const)'' is still copying the array in each function call!,
`attribute (const)' is not the same as declaring a constant.
Sorry, I couldn't have figured out that from manual.
Besides this, since array [0..255] can be and probably should be properly aligned on 32-bit boundary,
Arrays are generally aligned the same as their elements.
That's fine, but I would like to align i.e. this char array to the cache-line boundary: to start at i686's cache line. This way prefetch of data would IMHO be most efficient.
You've surely noticed that I'm trying to learn some general behavior and rules for writting optimal code, it's more than just this DigitValue() ... ;-)
(And_then is an equivalent of {B+}, isn't it?)
No, it's just the opposite.
I thought and_then is the short-circuit version of "and".
stuff, IMHO. So, we save both time and space :-)
How often do you call the function (in the same unit), so it would save the space of that array?
Yes, in this particular example I guess you proved your point considering space.
But please note Chuck's comment on EBCDIC: if then rules and conversion function rely on being in ASCII or similar charset, while array and Chuck's initialization functions (with some loops, hopefully) are quite more general.
Besides that, consider the timing: right now array is 13% faster, and in inlined version (without fun. entry/exit) this would be even more to the array version of routine side, after removing constant call penalty ...
Mirsad
Mirsad Todorovac wrote:
Arrays are generally aligned the same as their elements.
That's fine, but I would like to align i.e. this char array to the cache-line boundary: to start at i686's cache line. This way prefetch of data would IMHO be most efficient.
Then use an alignment attribute.
(And_then is an equivalent of {B+}, isn't it?)
No, it's just the opposite.
I thought and_then is the short-circuit version of "and".
Yes.
Frank
Mirsad Todorovac wrote:
On Sun, 8 Jun 2003, Frank Heckenbach wrote:
... snip ...
BTW, since you only access the array in the range '0' .. 'z', you only need to declare this part and can omit the lots of `-1' entries. Also, char indices are perfectly alright, so you don't have to use `Ord' here.
Thanks for reminding me. I chose to remove that if a in ['0'..'z'] ...
That is still a non-portable statement. There is no guarantee that '0' is less than 'z' (See EBCDIC for an example). The only ordering guarantee is on the numeric digits.
On Mon, 9 Jun 2003, CBFalconer wrote:
Mirsad Todorovac wrote:
On Sun, 8 Jun 2003, Frank Heckenbach wrote:
... snip ...
BTW, since you only access the array in the range '0' .. 'z', you only need to declare this part and can omit the lots of `-1' entries. Also, char indices are perfectly alright, so you don't have to use `Ord' here.
Thanks for reminding me. I chose to remove that if a in ['0'..'z'] ...
That is still a non-portable statement. There is no guarantee that '0' is less than 'z' (See EBCDIC for an example). The only ordering guarantee is on the numeric digits.
I saw EBCDIC and I was frightened.
I don't know how many routines would have to be rewritten in String and String2 units to fit in ... So, if it's not a scrict requirement, or if it doesn't become one day, I don't know if it is worthwhile ...
Did anybody run GNU Pascal on EBCDIC platform yet?
Mirsad
Mirsad Todorovac wrote:
I saw EBCDIC and I was frightened.
I don't know how many routines would have to be rewritten in String and String2 units to fit in ... So, if it's not a scrict requirement, or if it doesn't become one day, I don't know if it is worthwhile ...
Did anybody run GNU Pascal on EBCDIC platform yet?
GCC only supports ASCII platforms, and it's quite unlikely this will ever change. (After all, EBCDIC is still proprietary and secret outside of IBM, AFAIK, so it might not even be possible to support it.)
Anyway, at the time Wirth designed Pascal, the question of character sets was probably a valid issue. Today, we have ISO-8859-x, Unicode, etc., but they all have ASCII as their common base, so it's pretty safe to rely on that (certainly for GPC).
Frank
Frank Heckenbach wrote:
Mirsad Todorovac wrote:
I saw EBCDIC and I was frightened.
I don't know how many routines would have to be rewritten in String and String2 units to fit in ... So, if it's not a scrict requirement, or if it doesn't become one day, I don't know if it is worthwhile ...
Did anybody run GNU Pascal on EBCDIC platform yet?
GCC only supports ASCII platforms, and it's quite unlikely this will ever change. (After all, EBCDIC is still proprietary and secret outside of IBM, AFAIK, so it might not even be possible to support it.)
GCC supports EBCDIC (grep in gcc/ for EBCDIC), for example i370-ibm-mvs is a valid configuration and it uses natively EBCDIC. AFAIK there is a GCC version targeting mvs-3.8 and running on Hercules.
Anyway, at the time Wirth designed Pascal, the question of character sets was probably a valid issue. Today, we have ISO-8859-x, Unicode, etc., but they all have ASCII as their common base, so it's pretty safe to rely on that (certainly for GPC).
Unicode is more likely to case problem then EBCDIC -- simple test if something is a digit gets quite hairy.
Waldek Hebisch wrote:
Frank Heckenbach wrote:
Mirsad Todorovac wrote:
I saw EBCDIC and I was frightened.
I don't know how many routines would have to be rewritten in String and String2 units to fit in ... So, if it's not a scrict requirement, or if it doesn't become one day, I don't know if it is worthwhile ...
Did anybody run GNU Pascal on EBCDIC platform yet?
GCC only supports ASCII platforms, and it's quite unlikely this will ever change. (After all, EBCDIC is still proprietary and secret outside of IBM, AFAIK, so it might not even be possible to support it.)
GCC supports EBCDIC (grep in gcc/ for EBCDIC),
Oh yes (I only looked in doc/, silly me ...). Apparently it supports one EBCDIC variant, but only for lexing etc. The runtime support is probably left to the system library (as usual in C), while `char' just gives an integer type that can hold some values that may be interpreted as chars.
In Pascal, we'd have to do much more. As Mirsad pointed out, there are a lot of functions that would need adaptation. I don't really suppose this will happen too soon ... ;-)
Unicode is more likely to case problem then EBCDIC -- simple test if something is a digit gets quite hairy.
I'm not familiar with all the details of Unicode, but which other representations are there for (Arabic) digits?
Frank
Frank Heckenbach wrote:
I'm not familiar with all the details of Unicode, but which other representations are there for (Arabic) digits?
Zero have the following codes (all in hex): 0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; 06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; 0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;;
Waldek Hebisch wrote:
Frank Heckenbach wrote:
I'm not familiar with all the details of Unicode, but which other representations are there for (Arabic) digits?
Zero have the following codes (all in hex): 0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; 06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; 0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;;
So that's other number systems. I'm not familiar with them, but I don't think that all programs will (should) allow them. Just like Pascal, e.g., only allows English letters in identifiers (for good reasons) -- this issue occurs already with 8-bit charsets such as Latin-n --, I think a compiler etc. also should only accept ASCII digits for numbers (this issue indeed only occurs with Unicode, AFAIK).
Frank
Frank Heckenbach wrote:
Mirsad Todorovac wrote:
I saw EBCDIC and I was frightened.
I don't know how many routines would have to be rewritten in String and String2 units to fit in ... So, if it's not a scrict requirement, or if it doesn't become one day, I don't know if it is worthwhile ...
Did anybody run GNU Pascal on EBCDIC platform yet?
GCC only supports ASCII platforms, and it's quite unlikely this will ever change. (After all, EBCDIC is still proprietary and secret outside of IBM, AFAIK, so it might not even be possible to support it.)
OK, but let's document that in some fairly prominent place. AFAIK this limitation does not apply to gcc.
CBFalconer wrote:
OK, but let's document that in some fairly prominent place. AFAIK this limitation does not apply to gcc.
Will do.
Frank