Quantcast

Precedence issue with expr

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Precedence issue with expr

Brian Griffin-4
I just ran into a precedence issue with expr where it does not match C precedence.

$ cat test.c
#include <stdio.h>

double FNday (int y, int m, int d, float h) {
  long int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;
  luku+= (long int)y*367;
  return (double)luku - 730531.5 + h/24.0;
};

int main()
{
  double d = FNday(2017, 5, 15, 12);
  printf("d=%g\n",d);
}

$ make test
cc     test.c   -o test

$ ./test
d=6344

$ cat test.tcl
proc FNday {y m d h} {
    set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]
    set luku [expr {$luku + $y*367}]
    return [expr {double($luku) - 730531.5 + $h/24.0}]
}

proc main {} {
    set d [FNday 2017 5 15 12]
    puts d=$d
}

main

$ tclsh8.6 test.tcl
d=6343.0


Note that the answer from C does not match the answer from Tcl for the identical expression.
The issue is the left to right precedence of a multiple divide sequence, here:

    7 * (...) / 4

and here:

    275 * $m / 9

C operates left to right, but Tcl appears to operate right to left.  For integer arithmetic, divide before multiple looses precision, consequently Tcl comes up with a smaller, incorrect, answer.

-Brian


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Arjen Markus-3

Hi Brian,

 

Which version of Tcl are you using? I just tried the example and get no difference between:

 

expr {275 * $m / 9} and expr {(275 * $m) / 9}

 

(m set to 5 and 83 – both cases give the same answer)

 

(Note: I have not tried the full blown calculation you posted)

 

Regards,

 

Arjen

> -----Original Message-----
> From: Brian Griffin [[hidden email]]
> Sent: Tuesday, May 16, 2017 6:57 AM
> To: Tcl Core Mailing List
> Subject: [TCLCORE] Precedence issue with expr
>
> I just ran into a precedence issue with expr where it does not match C precedence.
>
> $ cat test.c
> #include <stdio.h>
>
> double FNday (int y, int m, int d, float h) {
>   long int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;
>   luku+= (long int)y*367;
>   return (double)luku - 730531.5 + h/24.0; };
>
> int main()
> {
>   double d = FNday(2017, 5, 15, 12);
>   printf("d=%g\n",d);
> }
>
> $ make test
> cc     test.c   -o test
>
> $ ./test
> d=6344
>
> $ cat test.tcl
> proc FNday {y m d h} {
>     set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]
>     set luku [expr {$luku + $y*367}]
>     return [expr {double($luku) - 730531.5 + $h/24.0}] }
>
> proc main {} {
>     set d [FNday 2017 5 15 12]
>     puts d=$d
> }
>
> main
>
> $ tclsh8.6 test.tcl
> d=6343.0
>
>
> Note that the answer from C does not match the answer from Tcl for the identical
> expression.
> The issue is the left to right precedence of a multiple divide sequence, here:
>
>     7 * (...) / 4
>
> and here:
>
>     275 * $m / 9
>
> C operates left to right, but Tcl appears to operate right to left.  For integer
> arithmetic, divide before multiple looses precision, consequently Tcl comes up with
> a smaller, incorrect, answer.
>
> -Brian
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most engaging tech
> sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Tcl-Core mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/tcl-core

DISCLAIMER: This message is intended exclusively for the addressee(s) and may contain confidential and privileged information. If you are not the intended recipient please notify the sender immediately and destroy this message. Unauthorized use, disclosure or copying of this message is strictly prohibited. The foundation 'Stichting Deltares', which has its seat at Delft, The Netherlands, Commercial Registration Number 41146461, is not liable in any way whatsoever for consequences and/or damages resulting from the improper, incomplete and untimely dispatch, receipt and/or content of this e-mail.
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Christian Gollwitzer
In reply to this post by Brian Griffin-4
Am 16.05.17 um 06:56 schrieb Brian Griffin:

> proc FNday {y m d h} {
>      set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]
>      set luku [expr {$luku + $y*367}]
>      return [expr {double($luku) - 730531.5 + $h/24.0}]
> }
>
> proc main {} {
>      set d [FNday 2017 5 15 12]
>      puts d=$d
> }
>
> main
>
> $ tclsh8.6 test.tcl
> d=6343.0
>
>
> Note that the answer from C does not match the answer from Tcl for the identical expression.
> The issue is the left to right precedence of a multiple divide sequence, here:
>
>      7 * (...) / 4
>
> and here:
>
>      275 * $m / 9


I can confirm that this code returns 6343 in Tcl 8.6.5, but the analysis
is wrong. Looking at the disassembly, the first expression gives:

::tcl::unsupported::disassemble proc FNday
ByteCode 0x0x1013c7610, refCt 1, epoch 16, interp 0x0x100c78a10 (epoch 16)
   Source "\n    set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*..."
   Cmds 6, src 158, inst 78, litObjs 9, aux 0, stkDepth 4, code/src 0.00
   Proc 0x0x100d55090, refCt 1, args 4, compiled locals 5
       slot 0, scalar, arg, "y"
       slot 1, scalar, arg, "m"
       slot 2, scalar, arg, "d"
       slot 3, scalar, arg, "h"
       slot 4, scalar, "luku"
   Commands 6:
       1: pc 0-31, src 5-64        2: pc 0-28, src 15-63
       3: pc 32-51, src 70-101        4: pc 41-48, src 80-100
       5: pc 52-76, src 107-156        6: pc 61-75, src 115-155
   Command 1: "set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 +..."
   Command 2: "expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}..."
     (0) push1 0 # "-7"
     (2) loadScalar1 %v0 # var "y"
     (4) loadScalar1 %v1 # var "m"
     (6) push1 1 # "9"
     (8) add
     (9) push1 2 # "12"
     (11) div
     (12) add
     (13) mult

clearly here the -7 * is ended

     (14) push1 3 # "4"
     (16) div

and divided by 4 here afterwards

     (17) push1 4 # "275"
     (19) loadScalar1 %v1 # var "m"
     (21) mult
     (22) push1 1 # "9"
     (24) div
     (25) add
     (26) loadScalar1 %v2 # var "d"
     (28) add
     (29) storeScalar1 %v4 # var "luku"
     (31) pop

It turns out, that Tcl uses different rounding rules for integer
division. In Tcl, expr -7/4 gives -2, while in C it gives -1. The code
for this difference is here:
https://github.com/tcltk/tcl/blob/master/generic/tclExecute.c#L6081
Maybe the experts can comment why this was chosen.

        Christian


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Arjen Markus-3

Hi Christian, Brian,

 

Ah! That is indeed a – documented – difference between Tcl and C. While I have not been involved in the choice for either C or Tcl wrt this operation, I think Tcl’s choice is much closer to mathematical modulo than C’s choice is. C’s choice seems to implement truncation. Also note that unary minus in Tcl binds strongly:

 

-7 * $m / 4

 

is actually interpreted as (-7) * $m / 4. That does not matter in many circumstances, but it does in this case.

 

Regards,

 

Arjen

> -----Original Message-----
> From: Christian Gollwitzer [[hidden email]]
> Sent: Tuesday, May 16, 2017 9:04 AM
> To: [hidden email]
> Subject: Re: [TCLCORE] Precedence issue with expr
>
> Am 16.05.17 um 06:56 schrieb Brian Griffin:
> > proc FNday {y m d h} {
> >      set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]
> >      set luku [expr {$luku + $y*367}]
> >      return [expr {double($luku) - 730531.5 + $h/24.0}] }
> >
> > proc main {} {
> >      set d [FNday 2017 5 15 12]
> >      puts d=$d
> > }
> >
> > main
> >
> > $ tclsh8.6 test.tcl
> > d=6343.0
> >
> >
> > Note that the answer from C does not match the answer from Tcl for the identical
> expression.
> > The issue is the left to right precedence of a multiple divide sequence, here:
> >
> >      7 * (...) / 4
> >
> > and here:
> >
> >      275 * $m / 9
>
>
> I can confirm that this code returns 6343 in Tcl 8.6.5, but the analysis is wrong.
> Looking at the disassembly, the first expression gives:
>
> ::tcl::unsupported::disassemble proc FNday ByteCode 0x0x1013c7610, refCt 1,
> epoch 16, interp 0x0x100c78a10 (epoch 16)
>    Source "\n    set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*..."
>    Cmds 6, src 158, inst 78, litObjs 9, aux 0, stkDepth 4, code/src 0.00
>    Proc 0x0x100d55090, refCt 1, args 4, compiled locals 5
>        slot 0, scalar, arg, "y"
>        slot 1, scalar, arg, "m"
>        slot 2, scalar, arg, "d"
>        slot 3, scalar, arg, "h"
>        slot 4, scalar, "luku"
>    Commands 6:
>        1: pc 0-31, src 5-64        2: pc 0-28, src 15-63
>        3: pc 32-51, src 70-101        4: pc 41-48, src 80-100
>        5: pc 52-76, src 107-156        6: pc 61-75, src 115-155
>    Command 1: "set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 +..."
>    Command 2: "expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}..."
>      (0) push1 0      # "-7"
>      (2) loadScalar1 %v0      # var "y"
>      (4) loadScalar1 %v1      # var "m"
>      (6) push1 1      # "9"
>      (8) add
>      (9) push1 2      # "12"
>      (11) div
>      (12) add
>      (13) mult
>
> clearly here the -7 * is ended
>
>      (14) push1 3     # "4"
>      (16) div
>
> and divided by 4 here afterwards
>
>      (17) push1 4     # "275"
>      (19) loadScalar1 %v1     # var "m"
>      (21) mult
>      (22) push1 1     # "9"
>      (24) div
>      (25) add
>      (26) loadScalar1 %v2     # var "d"
>      (28) add
>      (29) storeScalar1 %v4    # var "luku"
>      (31) pop
>
> It turns out, that Tcl uses different rounding rules for integer division. In Tcl, expr -
> 7/4 gives -2, while in C it gives -1. The code for this difference is here:
> https://github.com/tcltk/tcl/blob/master/generic/tclExecute.c#L6081
> Maybe the experts can comment why this was chosen.
>
>       Christian
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most engaging tech
> sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Tcl-Core mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/tcl-core

DISCLAIMER: This message is intended exclusively for the addressee(s) and may contain confidential and privileged information. If you are not the intended recipient please notify the sender immediately and destroy this message. Unauthorized use, disclosure or copying of this message is strictly prohibited. The foundation 'Stichting Deltares', which has its seat at Delft, The Netherlands, Commercial Registration Number 41146461, is not liable in any way whatsoever for consequences and/or damages resulting from the improper, incomplete and untimely dispatch, receipt and/or content of this e-mail.
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Donald Arseneau
In reply to this post by Brian Griffin-4
> Brian Griffin <[hidden email]> wrote
> I just ran into a precedence issue with expr where it does not match C
> precedence.
>   long int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;

vs

>     set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]

> The issue is the left to right precedence of a multiple divide sequence,

Nope.  The issue is different definitions of negative integer division.
C uses round towards zero, and Tcl is using round down.

Compare [expr (-7)/2]  vs  int n=(-7)/2

You can correct your Tcl expression by doing the divisions
while positive:

set luku [expr {- (7 * ($y + ($m + 9)/12)/4) + 275*$m/9 + $d}]

Since this is the Tcl-core list, I note that the expr manpage could
better mention 'rounding down' along with its example '“-57 / 10” is
always -6', and the somewhat esoteric description of segmenting the
number-line.


Donald Arseneau, TRIUMF CMMS, [hidden email]


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Dipl. Ing. Sergey G. Brester
In reply to this post by Brian Griffin-4

This goes to the div/mod pair that in TCL opposite to C is more "sign-safe".

In tcl (and another script languages) the sign of the result of modulo is the same as for divisor (in C - as dividend). Accordingly the division/modulo pair with negative dividend looks different compared to C:

  -2(1) in Tcl and -1(-3) in C.

For example:

% # tcl:
% puts "[set d [expr {-7 / 4}]] * 4 + [set m [expr {-7 % 4}]] == [expr {$d * 4 + $m}]"
-2 * 4 + 1 == -7

// C:
d = -7 / 4; m = -7 % 4; b = d * 4 + m; printf("%d * 4 + %d == %d", d, m, b);
-1 * 4 + -3 == -7

But as already said, it is not Tcl special handling, see for example Python:

>>> d = -7 / 4; m = -7 % 4; b = d * 4 + m; "{d} * 4 + {m} == {b}".format(**locals())
-2 * 4 + 1 == -7

Regards,
sebres.

Am 16.05.2017 06:56, schrieb Brian Griffin:

I just ran into a precedence issue with expr where it does not match C precedence.

$ cat test.c
#include <stdio.h>

double FNday (int y, int m, int d, float h) {
  long int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;
  luku+= (long int)y*367;
  return (double)luku - 730531.5 + h/24.0;
};

int main()
{
  double d = FNday(2017, 5, 15, 12);
  printf("d=%g\n",d);
}

$ make test
cc     test.c   -o test

$ ./test
d=6344

$ cat test.tcl
proc FNday {y m d h} {
    set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]
    set luku [expr {$luku + $y*367}]
    return [expr {double($luku) - 730531.5 + $h/24.0}]
}

proc main {} {
    set d [FNday 2017 5 15 12]
    puts d=$d
}

main

$ tclsh8.6 test.tcl
d=6343.0


Note that the answer from C does not match the answer from Tcl for the identical expression.
The issue is the left to right precedence of a multiple divide sequence, here:

    7 * (...) / 4

and here:

    275 * $m / 9

C operates left to right, but Tcl appears to operate right to left.  For integer arithmetic, divide before multiple looses precision, consequently Tcl comes up with a smaller, incorrect, answer.

-Brian


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Martin Lemburg
In reply to this post by Christian Gollwitzer
Gesendet: Dienstag, 16. Mai 2017 um 09:04 Uhr
Von: "Christian Gollwitzer" <[hidden email]>
An: "[hidden email]" <[hidden email]>
Betreff: Re: [TCLCORE] Precedence issue with expr
Am 16.05.17 um 06:56 schrieb Brian Griffin:

> > proc FNday {y m d h} {
> > set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]
> > set luku [expr {$luku + $y*367}]
> > return [expr {double($luku) - 730531.5 + $h/24.0}]
> > }
> >
> > proc main {} {
> > set d [FNday 2017 5 15 12]
> > puts d=$d
> > }
> >
> > main
> >
> > $ tclsh8.6 test.tcl
> > d=6343.0
> >
> >
> > Note that the answer from C does not match the answer from Tcl for the identical expression.
> > The issue is the left to right precedence of a multiple divide sequence, here:
> >
> > 7 * (...) / 4
> >
> > and here:
> >
> > 275 * $m / 9
>
>
> I can confirm that this code returns 6343 in Tcl 8.6.5, but the analysis
> is wrong. Looking at the disassembly, the first expression gives:
>
> ::tcl::unsupported::disassemble proc FNday
> ByteCode 0x0x1013c7610, refCt 1, epoch 16, interp 0x0x100c78a10 (epoch 16)
> Source "\n set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*..."
> Cmds 6, src 158, inst 78, litObjs 9, aux 0, stkDepth 4, code/src 0.00
> Proc 0x0x100d55090, refCt 1, args 4, compiled locals 5
> slot 0, scalar, arg, "y"
> slot 1, scalar, arg, "m"
> slot 2, scalar, arg, "d"
> slot 3, scalar, arg, "h"
> slot 4, scalar, "luku"
> Commands 6:
> 1: pc 0-31, src 5-64 2: pc 0-28, src 15-63
> 3: pc 32-51, src 70-101 4: pc 41-48, src 80-100
> 5: pc 52-76, src 107-156 6: pc 61-75, src 115-155
> Command 1: "set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 +..."
> Command 2: "expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}..."
> (0) push1 0 # "-7"
> (2) loadScalar1 %v0 # var "y"
> (4) loadScalar1 %v1 # var "m"
> (6) push1 1 # "9"
> (8) add
> (9) push1 2 # "12"
> (11) div
> (12) add
> (13) mult
>
> clearly here the -7 * is ended
>
> (14) push1 3 # "4"
> (16) div
>
> and divided by 4 here afterwards
>
> (17) push1 4 # "275"
> (19) loadScalar1 %v1 # var "m"
> (21) mult
> (22) push1 1 # "9"
> (24) div
> (25) add
> (26) loadScalar1 %v2 # var "d"
> (28) add
> (29) storeScalar1 %v4 # var "luku"
> (31) pop
>
> It turns out, that Tcl uses different rounding rules for integer
> division. In Tcl, expr -7/4 gives -2, while in C it gives -1. The code
> for this difference is here:
> https://github.com/tcltk/tcl/blob/master/generic/tclExecute.c#L6081
> Maybe the experts can comment why this was chosen.
>
> Christian

Isn't the rule applied, that should only be applied for integers > 0:

    % expr {6/4.}
    1.5
    % expr {6/4}
    1

Same as:

    % expr {round(floor(6/4.))}
    1
    % expr {int(6/4.)}
    1

In C the behavior seems to depend on the C standard C89 or C99.

C99 "truncates towards zero" (depending on the Fortran Standard), while C89 has implementation dependent behavior for negative operands.
But many implementations seem to "floor" the result of a division with negative operands.

    https://groups.google.com/forum/#!msg/comp.std.c/hjGK3cx_I-o/_zB17QyViDgJ
    https://stackoverflow.com/questions/3602827/what-is-the-behavior-of-integer-division-in-c
    https://stackoverflow.com/questions/8617010/integer-division-in-c11

Since I'm only using tcl and not building tcl … which C standard is expected for compiling tcl?

If tcl expects C99 standard, than the behavior should eventually be changed to match the C99 standard.

Best regards,
 
Martin Lemburg
Berlin / Germany

[hidden email]
http://about.me/Martin0815


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Donal K. Fellows-2
In reply to this post by Brian Griffin-4
On 16/05/2017 05:56, Brian Griffin wrote:
> C operates left to right, but Tcl appears to operate right to left.

I can see no evidence of that. Tcl's very strict about the order of
evaluation, much stricter than C. Actually, we can disassemble the Tcl
code to see exactly what order of operations will be performed (provided
we know how to read the stack operations in the bytecode):

% tcl::unsupported::disassemble proc FNday
ByteCode 0x0x103076410, refCt 1, epoch 15, interp 0x0x100829a10 (epoch 15)
   Source "\n    set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*"...
   Cmds 6, src 158, inst 78, litObjs 9, aux 0, stkDepth 4, code/src 0.00
   Proc 0x0x100861790, refCt 1, args 4, compiled locals 5
       slot 0, scalar, arg, "y"
       slot 1, scalar, arg, "m"
       slot 2, scalar, arg, "d"
       slot 3, scalar, arg, "h"
       slot 4, scalar, "luku"
   Commands 6:
       1: pc 0-31, src 5-64        2: pc 0-28, src 15-63
       3: pc 32-51, src 70-101        4: pc 41-48, src 80-100
       5: pc 52-76, src 107-156        6: pc 61-75, src 115-155
   Command 1: "set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 +"...
   Command 2: "expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}"...
     (0) push1 0 # "-7"
     (2) loadScalar1 %v0 # var "y"
     (4) loadScalar1 %v1 # var "m"
     (6) push1 1 # "9"
     (8) add
     (9) push1 2 # "12"
     (11) div
     (12) add
     (13) mult
     (14) push1 3 # "4"
     (16) div
     (17) push1 4 # "275"
     (19) loadScalar1 %v1 # var "m"
     (21) mult
     (22) push1 1 # "9"
     (24) div
     (25) add
     (26) loadScalar1 %v2 # var "d"
     (28) add
     (29) storeScalar1 %v4 # var "luku"
     (31) pop
   Command 3: "set luku [expr {$luku + $y*367}]"...
     (32) startCommand +19 2 # next cmd at pc 51, 2 cmds start here
   Command 4: "expr {$luku + $y*367}"...
     (41) loadScalar1 %v4 # var "luku"
     (43) loadScalar1 %v0 # var "y"
     (45) push1 5 # "367"
     (47) mult
     (48) add
     (49) storeScalar1 %v4 # var "luku"
     (51) pop
   Command 5: "return [expr {double($luku) - 730531.5 + $h/24.0}]"...
     (52) startCommand +25 2 # next cmd at pc 77, 2 cmds start here
   Command 6: "expr {double($luku) - 730531.5 + $h/24.0}"...
     (61) push1 6 # "tcl::mathfunc::double"
     (63) loadScalar1 %v4 # var "luku"
     (65) invokeStk1 2
     (67) push1 7 # "730531.5"
     (69) sub
     (70) loadScalar1 %v3 # var "h"
     (72) push1 8 # "24.0"
     (74) div
     (75) add
     (76) done
     (77) done

***HOWEVER,*** Tcl's division operator has different semantics to C's
when working with negative numbers. Though both C and Tcl both guarantee
that $a = ($a / $b) * $b + ($a % $b) (for integer $a and integer
non-zero $b), the actual values of ($a/$b) and ($a%$b) will differ; Tcl
guarantees that the sgn($a%$b) is sgn($b) and that 0 <= abs($a%$b) <
abs($b); it's the guarantee of sgn() that differs (and makes for varying
semantics). Basically, the result is that things round the other way in
the two languages.

I've not verified that this is the problem… but it looks like it might
be relevant as you've got negation and division.

Donal.

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core

donal_k_fellows.vcf (241 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Peter da Silva-2
In reply to this post by Donald Arseneau
On 5/16/17, 2:28 AM, "Donald Arseneau" <[hidden email]> wrote:
> Since this is the Tcl-core list, I note that the expr manpage could better mention 'rounding down' along with its example '“-57 / 10” is always -6', and the somewhat esoteric description of segmenting the number-line.

That part could perhaps be put in a separate motivation section. The difference in div/mod behavior in Tcl (and in Forth, where I first encountered this behavior) means that there is no “singularity” at zero when using div/mod operations for control or simulation.

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Kevin Kenny-6
Tcl's rounding rule for integer division is different from C99. C89
left the behaviour 'implementation-defined', which is to say that the
implementor had several choices and needed to document which was
chosen.

Tcl's decision predates the C99 standard and was made
consciously. Tcl's behaviour does not depend on the behaviour of the
underlying C implementation. The code that performs integer division
is careful to avoid or compensate for those cases that the C89
standard left to the implementor.

As Peter pointed out, the result that we chose for (-a % b) means that
there is no change in the behaviour of 'modulo' at zero. If we
calculate the results of ($x % 7), it continues repeating with period
7 along the entire number line, rather than changing sign and having
an inconsistent behaviour across the origin. This is useful in
simulation and control, in calendrical calculations such as Zeller's
congruence, and in number theory. For positive divisors, it's the
standard definition of 'modulo' in mathematics.

The result of modulo, in turn, determines the result of divison. The
identity

    ($a == $b * ($a / $b) + ($a % $b)

is an absolute requirement. For one to be inconsistent with the other
is entirely unacceptable.

The 'correct' behaviour for a negative divisor is less clear. Few
applications choose to compute residues modulo a negative number, so
that offers little guidance. What eventually drove the decision was
the desire to have the identity:

   (-$a / -$b) == ($a / $b)

Once this identity is asserted, then 'modulo' is required to behave
in conformance with it.

It is true that the behaviour is different from that specified in
C99. Tcl is not C.

Tcl's behaviour was chosen for mathematical consistency.
By contrast, it appears that C's behaviour was chosen because
it was what the native integer division instructions on a plurality
of CPU's happened to implement. I prefer consistency to
popularity.

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Donal K. Fellows-2
On 16/05/2017 13:58, Kevin Kenny wrote:
> Tcl's rounding rule for integer division is different from C99. C89
> left the behaviour 'implementation-defined', which is to say that the
> implementor had several choices and needed to document which was
> chosen.

Also we document it to be exactly this.
https://www.tcl.tk/man/tcl8.6/TclCmd/expr.htm#M9

> When applied to integers, the division and remainder operators can be
> considered to partition the number line into a sequence of
> equal-sized adjacent non-overlapping pieces where each piece is the
> size of the divisor; the division result identifies which piece the
> divisor lay within, and the remainder result identifies where within
> that piece the divisor lay. A consequence of this is that the result
> of “-57 / 10” is always -6, and the result of “-57 % 10” is always 3.

We perhaps ought to explicitly note that this is different to C99, and
some of the motivation for this difference.

Donal.

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core

donal_k_fellows.vcf (241 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Brian Griffin-4
In reply to this post by Arjen Markus-3
Thank you all for the analysis and explanation.  I stand corrected!

I translated some C code, performing a complex calculation, to Tcl and spent some time trying to figure out why Tcl came up with a completely different result.  I'll assume it was the late hour that lead me to jump to conclusions, when I hit upon this expression as the culprit.

-Brian

On May 16, 2017, at 12:22 AM, Arjen Markus <[hidden email]> wrote:

Hi Christian, Brian,
 
Ah! That is indeed a – documented – difference between Tcl and C. While I have not been involved in the choice for either C or Tcl wrt this operation, I think Tcl’s choice is much closer to mathematical modulo than C’s choice is. C’s choice seems to implement truncation. Also note that unary minus in Tcl binds strongly:
 
-7 * $m / 4
 
is actually interpreted as (-7) * $m / 4. That does not matter in many circumstances, but it does in this case.
 
Regards,
 
Arjen

> -----Original Message-----
> From: Christian Gollwitzer [[hidden email]]
> Sent: Tuesday, May 16, 2017 9:04 AM
> To: [hidden email]
> Subject: Re: [TCLCORE] Precedence issue with expr
>
> Am 16.05.17 um 06:56 schrieb Brian Griffin:
> > proc FNday {y m d h} {
> >      set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}]
> >      set luku [expr {$luku + $y*367}]
> >      return [expr {double($luku) - 730531.5 + $h/24.0}] }
> >
> > proc main {} {
> >      set d [FNday 2017 5 15 12]
> >      puts d=$d
> > }
> >
> > main
> >
> > $ tclsh8.6 test.tcl
> > d=6343.0
> >
> >
> > Note that the answer from C does not match the answer from Tcl for the identical
> expression.
> > The issue is the left to right precedence of a multiple divide sequence, here:
> >
> >      7 * (...) / 4
> >
> > and here:
> >
> >      275 * $m / 9
>
>
> I can confirm that this code returns 6343 in Tcl 8.6.5, but the analysis is wrong.
> Looking at the disassembly, the first expression gives:
>
> ::tcl::unsupported::disassemble proc FNday ByteCode 0x0x1013c7610, refCt 1,
> epoch 16, interp 0x0x100c78a10 (epoch 16)
>    Source "\n    set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*..."
>    Cmds 6, src 158, inst 78, litObjs 9, aux 0, stkDepth 4, code/src 0.00
>    Proc 0x0x100d55090, refCt 1, args 4, compiled locals 5
>        slot 0, scalar, arg, "y"
>        slot 1, scalar, arg, "m"
>        slot 2, scalar, arg, "d"
>        slot 3, scalar, arg, "h"
>        slot 4, scalar, "luku"
>    Commands 6:
>        1: pc 0-31, src 5-64        2: pc 0-28, src 15-63
>        3: pc 32-51, src 70-101        4: pc 41-48, src 80-100
>        5: pc 52-76, src 107-156        6: pc 61-75, src 115-155
>    Command 1: "set luku [expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 +..."
>    Command 2: "expr {- 7 * ($y + ($m + 9)/12)/4 + 275*$m/9 + $d}..."
>      (0) push1 0      # "-7"
>      (2) loadScalar1 %v0      # var "y"
>      (4) loadScalar1 %v1      # var "m"
>      (6) push1 1      # "9"
>      (8) add
>      (9) push1 2      # "12"
>      (11) div
>      (12) add
>      (13) mult
>
> clearly here the -7 * is ended
>
>      (14) push1 3     # "4"
>      (16) div
>
> and divided by 4 here afterwards
>
>      (17) push1 4     # "275"
>      (19) loadScalar1 %v1     # var "m"
>      (21) mult
>      (22) push1 1     # "9"
>      (24) div
>      (25) add
>      (26) loadScalar1 %v2     # var "d"
>      (28) add
>      (29) storeScalar1 %v4    # var "luku"
>      (31) pop
>
> It turns out, that Tcl uses different rounding rules for integer division. In Tcl, expr -
> 7/4 gives -2, while in C it gives -1. The code for this difference is here:
> https://github.com/tcltk/tcl/blob/master/generic/tclExecute.c#L6081
> Maybe the experts can comment why this was chosen.
>
>       Christian
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most engaging tech
> sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Tcl-Core mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/tcl-core

DISCLAIMER: This message is intended exclusively for the addressee(s) and may contain confidential and privileged information. If you are not the intended recipient please notify the sender immediately and destroy this message. Unauthorized use, disclosure or copying of this message is strictly prohibited. The foundation 'Stichting Deltares', which has its seat at Delft, The Netherlands, Commercial Registration Number 41146461, is not liable in any way whatsoever for consequences and/or damages resulting from the improper, incomplete and untimely dispatch, receipt and/or content of this e-mail. ------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Precedence issue with expr

Martin Lemburg
In reply to this post by Kevin Kenny-6
Gesendet: Dienstag, 16. Mai 2017 um 14:58 Uhr
Von: "Kevin Kenny" <[hidden email]>
An: "[hidden email]" <[hidden email]>
Betreff: Re: [TCLCORE] Precedence issue with expr

>
> Tcl's rounding rule for integer division is different from C99. C89
> left the behaviour 'implementation-defined', which is to say that the
> implementor had several choices and needed to document which was
> chosen.
>
> Tcl's decision predates the C99 standard and was made
> consciously. Tcl's behaviour does not depend on the behaviour of the
> underlying C implementation. The code that performs integer division
> is careful to avoid or compensate for those cases that the C89
> standard left to the implementor.
>
> As Peter pointed out, the result that we chose for (-a % b) means that
> there is no change in the behaviour of 'modulo' at zero. If we
> calculate the results of ($x % 7), it continues repeating with period
> 7 along the entire number line, rather than changing sign and having
> an inconsistent behaviour across the origin. This is useful in
> simulation and control, in calendrical calculations such as Zeller's
> congruence, and in number theory. For positive divisors, it's the
> standard definition of 'modulo' in mathematics.
>
> The result of modulo, in turn, determines the result of divison. The
> identity
>
>     ($a == $b * ($a / $b) + ($a % $b)
>
> is an absolute requirement. For one to be inconsistent with the other
> is entirely unacceptable.
>
> The 'correct' behaviour for a negative divisor is less clear. Few
> applications choose to compute residues modulo a negative number, so
> that offers little guidance. What eventually drove the decision was
> the desire to have the identity:
>
>    (-$a / -$b) == ($a / $b)
>
> Once this identity is asserted, then 'modulo' is required to behave
> in conformance with it.
>
> It is true that the behaviour is different from that specified in
> C99. Tcl is not C.
> Tcl's behaviour was chosen for mathematical consistency.By contrast,
> it appears that C's behaviour was chosen becauseit was what the native
> integer division instructions on a pluralityof CPU's happened to implement.
> I prefer consistency topopularity

Hi Kevin,

I understand the choice and the reasons.

What I want to point out is, that many use tcl in an embedded environment and that this may be now problematic.
Either tcl is embedded in C/C++ or uses C/C++ libraries.
If results of calculations from C/C++ get used in tcl and otherwise and different behaviors in tcl and C/C++ gets together, I fear, that problems may arise.
If algorithms get ported from one side to the other, the even documented behavior of both sides of the world may get in conflict without knowledge of the developer.

And I know of developers using tcl - build for running in a specific microprocessor environment - for rapid development and "porting" back such "proof of concept" tcl scripts to C.

In times of C89 it was "conflict free", but now I see great chances for difficult to detect and to fix bugs and a dilemma - tcl sided stability Vs compatibility.

Best regards, 
 
Martin Lemburg
Berlin / Germany

[hidden email]
http://about.me/Martin0815

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Tcl-Core mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/tcl-core
Loading...