Message Boards Message Boards

GROUPS:

Why a function returns two different values in a Notebook and in a Package?

Posted 3 years ago
2315 Views
|
3 Replies
|
0 Total Likes
|

I have some Mathematica code that shows a behaviour I really cannot understand.

The code only contains a bunch of function definitions. If I paste it in the Notebook Front End and I evaluate it, I can then use those functions and they work as expected. Until here everything's fine.

The problems start when I try to create a Package with the same code. I exported the code from the Notebook to a Package and I saved to a file.m file. When I load the package with the command Get["path/to/file.m"], it is loaded correctly and the functions defined in the package become visible in the new Notebook where I loaded the package. The problem is that some functions (at the moment just one x2u) do not return the same results on evaluation if they are loaded from the package as if they were simply copy-pasted into the notebook.

I have read around several threads here, and also on stack exchange and in the documentation and I have already checked the following things in my code:

  • I know that when packages are loaded with Get[] only the initialization cell is evaluated. My Package is composed only by a single cell, which is also marked as Initialization Cell.

  • I know that Input Cells are discarded in Packages and only Code Cells are evaluated. The only cell in my Package is Code.

  • I know about $Context and $ContextPath and that some variables and functions defined in the Package can shadow globals. I am not sure I completely understood all the nuances of these concepts but I placed the function definitions in the private block of the package.

  • I also double-checked that the kernel was fresh in both cases:

  • when I executed the code directly from the Notebook
  • when I loaded the newly created package with the same code

After some work I managed to shrink the original Notebook to a minimal subset that reproduces the odd behaviour.

Here is the Notebook:

setenv[{e_Integer/;0<=e<=4,f_Integer/;0<=f<=11}]:=(
{esizesize,fsizesize}={e,f};
{esizemax,fsizemax}=
2^{e,f};
utagsize=1+f+e;
maxubits=1+esizemax+fsizemax+utagsize;
ubitmask=BitShiftLeft[1,utagsize-1];
fsizemask=(BitShiftLeft[1,f]-1);
esizemask=( ubitmask-1)-fsizemask;
efsizemask=BitOr[esizemask,fsizemask];
utagmask=BitOr[ ubitmask,efsizemask];
ulpu=BitShiftLeft[1,utagsize];
smallsubnormalu=efsizemask+ulpu;
smallnormalu=efsizemask+BitShiftLeft[1,maxubits-1-esizemax];
signbigu=BitShiftLeft[1,maxubits-1];
posinfu=signbigu-1- ubitmask;
maxrealu=posinfu-ulpu;
minrealu=maxrealu+signbigu;
neginfu=posinfu+signbigu;
negbigu=neginfu-ulpu;
qNaNu=posinfu+ ubitmask;
sNaNu=neginfu+ ubitmask;
negopeninfu=If[utagsize==1,2^^1101,BitShiftLeft[2^^1111,utagsize-1]];
posopeninfu=If[utagsize==1,2^^0101,BitShiftLeft[2^^0111,utagsize-1]];
negopenzerou=BitShiftLeft[2^^1001,utagsize-1];
maxreal=2^2^(esizemax-1) (2^fsizemax-1)/2^(fsizemax-1);
smallsubnormal=2^(2-2^(esizemax-1)-fsizemax);)

fsizeminus1[u_/;unumQ[u]]:=BitAnd[u,fsizemask]
fsize[u_/;unumQ[u]]:=1+fsizeminus1[u]
esizeminus1[u_/;unumQ[u]]:=BitShiftRight[BitAnd[u,esizemask],fsizesize]
esize[u_/;unumQ[u]]:=1+esizeminus1[u]

NaN=Indeterminate;

unumQ[x_]:=If[IntegerQ[x],If[x>=0\[And]x<=sNaNu,True,False],False]
floatQ[x_]:=If[NumericQ[x],If[Head[x]=!=Complex,True,False],If[x===\[Infinity]\[Or]x===-\[Infinity]\[Or]x===NaN,True,False]]

expovalue[u_/;unumQ[u]]:=expo[u]-bias[u]+1-hidden[u]
expomask[u_/;unumQ[u]]:=BitShiftLeft[BitShiftLeft[1,esize[u]]-1,fsize[u]+utagsize]
fracmask[u_/;unumQ[u]]:=BitShiftLeft[BitShiftLeft[1,fsize[u]]-1,utagsize]
bias[u_/;unumQ[u]]:=2^esizeminus1[u]-1
sign[u_/;unumQ[u]]:=Boole[BitAnd[u,signmask[u]]>0]
expo[u_/;unumQ[u]]:=BitShiftRight[BitAnd[u,expomask[u]],utagsize+fsize[u]]
hidden[u_/;unumQ[u]]:=Boole[expo[u]>0]
frac[u_/;unumQ[u]]:=BitShiftRight[BitAnd[u,fracmask[u]],utagsize]
exQ[u_/;unumQ[u]]:=BitAnd[ubitmask,u]==0
numbits[u_/;unumQ[u]]:=1+esize[u]+fsize[u]+utagsize
signmask[u_/;unumQ[u]]:=BitShiftLeft[1,numbits[u]-1]


scale[x_/;floatQ[x]\[And]x!=\[Infinity]\[And]x=!=NaN]:=If[x==0,0,\[LeftFloor]Log[2,Abs[x]]\[RightFloor]]
ne[x_/;floatQ[x]\[And]x!=\[Infinity]\[And]x=!=NaN]:=If[x==0\[Or]scale[x]==1,1,\[LeftCeiling]Log[2,1+Abs[scale[x]-1]]\[RightCeiling]+1]

x2u[x_/;floatQ[x]]:=Which[
x===NaN,qNaNu,
x==+\[Infinity],posinfu,
x==-\[Infinity],neginfu,
Abs[x]>maxreal,maxrealu+ubitmask+If[x<0,signbigu,0],
x==0,0,
Abs[x]<smallsubnormal,utagmask+If[x<0, signbigu,0],
Abs[x]<u2f[smallnormalu],
Module[{y},y=Abs[x]/smallsubnormal;
y=If[x<0, signbigu,0]+efsizemask+If[y!=\[LeftFloor]y\[RightFloor], ubitmask,0]+BitShiftLeft[\[LeftFloor]y\[RightFloor],utagsize];
While[BitAnd[BitShiftLeft[3,utagsize-1],y]==0,y=(y-BitAnd[efsizemask,y])/2+BitAnd[efsizemask,y]-1];y],
True,Module[{n=0,y,z},
y=Abs[x]/2^scale[x];n=0;While[\[LeftFloor]y\[RightFloor]!=y\[And]n<fsizemax,{n++,y*=2}];
If[y==\[LeftFloor]y\[RightFloor],y=n-Boole[n>0]
+BitShiftLeft[ne[x]-1,fsizesize]
+If[n==0,0,BitShiftLeft[\[LeftFloor]y\[RightFloor]-2^scale[y],utagsize]]
+BitShiftLeft[scale[x]+2^(ne[x]-1)-1,utagsize+n+Boole[n==0]]
+If[x<0,BitShiftLeft[1,utagsize+n+Boole[n==0]+ne[x]],0];
z=Log[2,1-Log[2,Abs[x]]];
If[IntegerQ[z]\[And]z>=0,BitShiftLeft[z,fsizesize]+ulpu+Boole[x<0]signmask[BitShiftLeft[z,fsizesize]],y],
(
z=\[LeftCeiling](Abs[x]/2^(scale[x]-fsizemax))\[RightCeiling]2^(scale[x]-fsizemax);n=Max[ne[x],ne[z]];
y=fsizemask
+BitShiftLeft[n-1,fsizesize]
+ ubitmask-ulpu
+BitShiftLeft[\[LeftFloor](z/2^scale[z]-1)2^fsizemax\[RightFloor],utagsize]
+BitShiftLeft[scale[z]+2^(n-1)-1,utagsize+fsizemax];
If[x<0,y+=signmask[y],y]
)]]]

u2f[u_/;unumQ[u]\[And]exQ[u]]:=Which[
u==posinfu,+\[Infinity],
u==neginfu,-\[Infinity],
True,(-1)^sign[u] 2^expovalue[u] (hidden[u]+frac[u]/2^fsize[u])]

If I evaluate it and then run following commands I get the following result which is correct. correct result

The code for the package instead is the following:

BeginPackage["minimal`"]

setenv::usage = "setenv[{esizesize, fsizesize}]"
x2u::usage = "x2u[float_number]"

Begin["`Private`"]
setenv[{e_Integer/;0<=e<=4,f_Integer/;0<=f<=11}]:=(
{esizesize,fsizesize}={e,f};
{esizemax,fsizemax}=
2^{e,f};
utagsize=1+f+e;
maxubits=1+esizemax+fsizemax+utagsize;
ubitmask=BitShiftLeft[1,utagsize-1];
fsizemask=(BitShiftLeft[1,f]-1);
esizemask=( ubitmask-1)-fsizemask;
efsizemask=BitOr[esizemask,fsizemask];
utagmask=BitOr[ubitmask,efsizemask];
ulpu=BitShiftLeft[1,utagsize];
smallsubnormalu=efsizemask+ulpu;
smallnormalu=efsizemask+BitShiftLeft[1,maxubits-1-esizemax];
signbigu=BitShiftLeft[1,maxubits-1];
posinfu=signbigu-1- ubitmask;
maxrealu=posinfu-ulpu;
minrealu=maxrealu+signbigu;
neginfu=posinfu+signbigu;
negbigu=neginfu-ulpu;
qNaNu=posinfu+ ubitmask;
sNaNu=neginfu+ ubitmask;
negopeninfu=If[utagsize==1,2^^1101,BitShiftLeft[2^^1111,utagsize-1]];
posopeninfu=If[utagsize==1,2^^0101,BitShiftLeft[2^^0111,utagsize-1]];
negopenzerou=BitShiftLeft[2^^1001,utagsize-1];
maxreal=2^2^(esizemax-1) (2^fsizemax-1)/2^(fsizemax-1);
smallsubnormal=2^(2-2^(esizemax-1)-fsizemax);)

fsizeminus1[u_/;unumQ[u]]:=BitAnd[u,fsizemask]
fsize[u_/;unumQ[u]]:=1+fsizeminus1[u]
esizeminus1[u_/;unumQ[u]]:=BitShiftRight[BitAnd[u,esizemask],fsizesize]
esize[u_/;unumQ[u]]:=1+esizeminus1[u]

NaN=Indeterminate;

unumQ[x_]:=If[IntegerQ[x],If[x>=0\[And]x<=sNaNu,True,False],False]
floatQ[x_]:=If[NumericQ[x],If[Head[x]=!=Complex,True,False],If[x===\[Infinity]\[Or]x===-\[Infinity]\[Or]x===NaN,True,False]]

expovalue[u_/;unumQ[u]]:=expo[u]-bias[u]+1-hidden[u]
expomask[u_/;unumQ[u]]:=BitShiftLeft[BitShiftLeft[1,esize[u]]-1,fsize[u]+utagsize]
fracmask[u_/;unumQ[u]]:=BitShiftLeft[BitShiftLeft[1,fsize[u]]-1,utagsize]
bias[u_/;unumQ[u]]:=2^esizeminus1[u]-1
sign[u_/;unumQ[u]]:=Boole[BitAnd[u,signmask[u]]>0]
expo[u_/;unumQ[u]]:=BitShiftRight[BitAnd[u,expomask[u]],utagsize+fsize[u]]
hidden[u_/;unumQ[u]]:=Boole[expo[u]>0]
frac[u_/;unumQ[u]]:=BitShiftRight[BitAnd[u,fracmask[u]],utagsize]
exQ[u_/;unumQ[u]]:=BitAnd[ubitmask,u]==0
numbits[u_/;unumQ[u]]:=1+esize[u]+fsize[u]+utagsize
signmask[u_/;unumQ[u]]:=BitShiftLeft[1,numbits[u]-1]

u2f[u_/;unumQ[u]\[And]exQ[u]]:=Which[
u==posinfu,+\[Infinity],
u==neginfu,-\[Infinity],
True,(-1)^sign[u] 2^expovalue[u] (hidden[u]+frac[u]/2^fsize[u])]
scale[x_/;floatQ[x]\[And]x!=\[Infinity]\[And]x=!=NaN]:=If[x==0,0,\[LeftFloor]Log[2,Abs[x]]\[RightFloor]]
ne[x_/;floatQ[x]\[And]x!=\[Infinity]\[And]x=!=NaN]:=If[x==0\[Or]scale[x]==1,1,\[LeftCeiling]Log[2,1+Abs[scale[x]-1]]\[RightCeiling]+1]

x2u[x_/;floatQ[x]]:=Which[
x===NaN,qNaNu,
x==+\[Infinity],posinfu,
x==-\[Infinity],neginfu,
Abs[x]>maxreal,maxrealu+ubitmask+If[x<0,signbigu,0],
x==0,0,
Abs[x]<smallsubnormal,utagmask+If[x<0, signbigu,0],
Abs[x]<u2f[smallnormalu],
Module[{y},y=Abs[x]/smallsubnormal;
y=If[x<0, signbigu,0]+efsizemask+If[y!=\[LeftFloor]y\[RightFloor], ubitmask,0]+BitShiftLeft[\[LeftFloor]y\[RightFloor],utagsize];
While[BitAnd[BitShiftLeft[3,utagsize-1],y]==0,y=(y-BitAnd[efsizemask,y])/2+BitAnd[efsizemask,y]-1];y],
True,Module[{n=0,y,z},
y=Abs[x]/2^scale[x];n=0;While[\[LeftFloor]y\[RightFloor]!=y\[And]n<fsizemax,{n++,y*=2}];
If[y==\[LeftFloor]y\[RightFloor],y=n-Boole[n>0]
+BitShiftLeft[ne[x]-1,fsizesize]
+If[n==0,0,BitShiftLeft[\[LeftFloor]y\[RightFloor]-2^scale[y],utagsize]]
+BitShiftLeft[scale[x]+2^(ne[x]-1)-1,utagsize+n+Boole[n==0]]
+If[x<0,BitShiftLeft[1,utagsize+n+Boole[n==0]+ne[x]],0];
z=Log[2,1-Log[2,Abs[x]]];
If[IntegerQ[z]\[And]z>=0,BitShiftLeft[z,fsizesize]+ulpu+Boole[x<0]signmask[BitShiftLeft[z,fsizesize]],y],
(
z=\[LeftCeiling](Abs[x]/2^(scale[x]-fsizemax))\[RightCeiling]2^(scale[x]-fsizemax);n=Max[ne[x],ne[z]];
y=fsizemask
+BitShiftLeft[n-1,fsizesize]
+ ubitmask-ulpu
+BitShiftLeft[\[LeftFloor](z/2^scale[z]-1)2^fsizemax\[RightFloor],utagsize]
+BitShiftLeft[scale[z]+2^(n-1)-1,utagsize+fsizemax];
If[x<0,y+=signmask[y],y]
)]]]

End[]
EndPackage[]

If I close Mathematica and reopen it (so that I am sure I have a fresh Kernel), and I try to Get[] the package and run the same commands as above I get the following wrong result. wrong result

What am I doing wrong?

Unfortunately the minimal example is not so minimal, but I didn't write the original code myself. It comes from a Notebook I got from the internet. It's a Notebook freely distributed with this book: http://crcpress.com/The-End-of-Error-Unum-Computing/Gustafson/p/book/9781482239867 You can find it in a .zip file in the Downloads/Updates tab, on the left, just below the picture of the book cover. In the original Notebook there is a ton of code, but the part I provided should be enough and self-contained and I have not been able to reduce it further. I also tried with some code I wrote, but I have not been able to obtain the same misbehaviour.

As you can see the code in the Notebook and in the Package are really the same, except for the BeginPackage[] EndPackage[] portions.

3 Replies

Looks like a possible problem with Get that is also coming from ToExpression

InputForm@ToExpression["Hold[\[LeftCeiling]Log[2,1+Abs[scale[x]-1]]\[RightCeiling]+1]"]

(* InputForm=Hold[Ceiling[Log[2, 1 + Abs[scale[x] - 1]]]*(Plus[1])] *)

Thanks, I will look in to it and see what happens with your suggestions. But given that the code is the same in the Notebook and the Package, I still don't understand, why are the results different?

1024 result from the package code comes from BitShiftLeft[2, 9]

1552 result from the Front End implementation comes from BitShiftLeft[3, 9] + 16

The difference in the BitShiftLeft first argument 2 vs 3: 2 + 2^(ne[x] - 1) - 1

Private ne in 2^(ne[4] - 1) - 1 is returning 1

The Package is interpreting [LeftCeiling] stuff [RightCeiling] + 1 into

Times[Ceiling[Log[2, Plus[1, Abs[Plus[scale[x], -1]]]]], Plus[1]]

I would go ahead and replace that line with

Ceiling[Log[2, 1 + Abs[scale[x] - 1]]] + 1

Then it will work for you.

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract