AmiBroker 6.22 64 bit difference vs 32 bit

As I have found new VC+2017 compiler aggressively optimized array divisions using

x/y -> x * (1/y)

substitution which introduces rounding errors of about 1 ulp (units at last place). Aggressive optimizations like this will be disabled in next BETA version 6.23

Hello Tomasz,
I have the same code, it works fine previous version and 6.22 32 bit, but look strange in 6.22 64bit.

Posting pictures without formula is pointless.

1 Like

The code here, please check.

GraphXSpace=0;
SetChartOptions(1, chartShowArrows|chartDisableTooltips);
{_SECTION_BEGIN("Method Setting");

Scaling = ParamList("Scaling Method", "Traditional|UserDefine"); 
Rev = Param("Reversal",1, 1, 10, 1);
BoxUser=Param( "$Box", 1, 0.01, 100, 0.1 ); 

if(scaling == "UserDefine")
{Box = BoxUser; }
if ( scaling == "Traditional" )
{
	FP= LastVisibleValue(C);
	Box = IIf(FP <= 0.25, 0.0625,
			IIf(FP>0.25 AND FP<=1.00, 0.125,
			IIf(FP>1.00 AND FP<=5.00, 0.250,
			IIf(FP>5.00 AND FP<=20.00, 0.50,
			IIf(FP>20.00 AND FP<=100.00, 1.00,
			IIf(FP>100.00 AND FP<=200.00, 2.00,
			IIf(FP>200.00 AND FP<=500.00, 4.00,
			IIf(FP>500.00 AND FP<=1000.00, 5.00,
			IIf(FP>1000.00 AND FP<=25000.00, 50.00, 500)))))))));			 
}
_SECTION_END();}
//================================================

function gfxDrwX(x,y,a,b)
{
	GfxSelectSolidBrush( colorGreen ); 
	GfxSelectPen( colorGreen,1); 
		
	GfxMoveTo(x-a,y+b);
	GfxLineTo(x+a,y-b);
	GfxMoveTo(x-a,y-b);
	GfxLineTo(x+a,y+b);
}
function GfxDrwEll(x,y,a,b)
{
	GfxSelectSolidBrush( colorRed ); 
	GfxSelectPen( colorRed,1 ); 
	GfxSelectStockObject(5);
	x1=x-a;
	y1=y+b;
	x2=x+a;
	y2=y-b;		
	GfxEllipse( x1, y1, x2,y2);
}
bi=BarIndex();
fvb = FirstVisibleValue(bi);
Lvb = LastVisibleValue(bi);
lv=LastValue(bi);
visiblebar=Min(lvb-fvb, BarCount-fvb);

BarTurn = 0;
BarEnd = 0;
ColNum=1;
BoxChg=1;

j=0;
YF=Box*round(C/Box);
YH=YF;
YL=YF;

dir=IIf(C >= O, 1, 0);
swab=0;
ret=Null;

//==================================
// PnF Close
//==================================
{_SECTION_BEGIN("PnF Close");

for(i=1; i<BarCount; i++)
{
	
	
	if(dir[j]==0)
	{
		if(C[i] <= YL[j] - Box) //cont dwn
		{
			chg=YL[j]-C[i];
			n=floor(chg/box);
			
			YH[j]=YF[j];
			YL[j]=YL[j] - n*Box;
			BarEnd[j] = Bi[i];
		}
		else
		{
			if(C[i] >= YL[j] + rev*Box) //rev up
			{
				chg=C[i]-YL[j];
				n=floor(chg/box);
				j++;
				swab[j]=1;
				Dir[j]=1;
				YF[j] = YL[j-1] + Box;
				YL[j]=YF[j];
				YH[j]=YL[j-1]+n*Box;
				BarTurn[j] = Bi[i];
				BarEnd[j] = Bi[i];
				ColNum[j] = ColNum[j] +j;
				
				while(swab[j]==1 AND i<BarCount) 
				{
					if(C[i] <= YF[j] - Box) //rev dwn 
					{
						chg=YF[j]-C[i];
						n=floor(chg/Box);
						
						YH[j]=YF[j];
						YL[j]=YF[j]-n*Box;
						
						BarEnd[j] = Bi[i];
						dir[j]=0;
						swab[j]=0;
						ret[j]=1;
						continue;
					}
					else
					{
						if(C[i]>=YF[j] + Box) //Cont up
						{
							chg=C[i]-YF[j];
							n=floor(chg/box);
							YL[j]=YF[j];
							YH[j]=YF[j]+n*box;
							BarEnd[j] = Bi[i];
							dir[j]=1;
							swab[j]=0;
							continue;
						}
					}
					i++;
				}
			}
		}
	}
	else
	{
		if(C[i] >= YH[j] + Box) //cont up
		{
			chg=C[i]-YH[j];
			n=floor(chg/box);
			
			YL[j]=YF[j];
			YH[j]=YH[j] + n*Box;
			BarEnd[j] = Bi[i];
			
		}
		else
		{
			if(C[i]<=YH[j] - rev*Box) // rev dwn
			{
				chg=YH[j]-C[i];
				n=floor(chg/box);
				j++;
				dir[j]=0;
				swab[j]=1;
				YF[j]=YH[j-1]-Box;
				YH[j]=YF[j];
				YL[j]=YH[j-1]- n*box;
				BarTurn[j] = Bi[i];
				BarEnd[j] = Bi[i];
				ColNum[j] = ColNum[j] +j;
				while(swab[j]==1 AND i<BarCount)
				{
					if(C[i]>=YF[j]+Box) // rev up
					{
						chg=C[i]-YF[j];
						n=floor(chg/box);
						
						YL[j]=YF[j];
						YH[j]=YF[j] + n*Box;
						BarEnd[j] = Bi[i];
						Dir[j]=1;
						swab[j]=0;
						ret[j]=1;
						continue;
					}
					else
					{
						if(C[i] <=YF[j] - Box) //cont dwn
						{
							chg=YF[j]-C[i];
							n=floor(chg/box);
							YH[j]=YF[j];
							YL[j]=YF[j]-n*box;
							BarEnd[j] = Bi[i];
							dir[j]=0;
							swab[j]=0;
							continue;
						}
					}
					i++;
				}
			}
		}
	}
	
}
_SECTION_END();}

delta=BarCount-1-j;
YF=Ref(YF, -delta);
YH=Ref(YH, -delta);
YL=Ref(YL, -delta);
ret=Ref(ret, -delta);
dir=Ref(dir, -delta);
ColNum = Ref(ColNum, -delta);
BarTurns = Ref( BarTurn, -delta);
BarEnds = Ref( BarEnd, -delta);
n=(YH-YL)/Box;

space=1;
GfxSetOverlayMode(0 ); 
GfxSetCoordsMode(1); 
GfxSetBkMode(2);
//======================
//Grid
//====================

ScreenHigh =HighestVisibleValue(YH)+2.5*Box;
ScreenLow = LowestVisibleValue(YL)-2.5*box;
gridColor = ColorRGB( 20,40,40);

format = 8.2;
shift = 10;
Plot(ScreenHigh,"",gridColor,styleLine|styleThick|styleNoLabel,Null,Null,shift);	
Plot(ScreenLow,"",gridColor,styleLine|styleThick|styleNoLabel,Null,Null,shift);
	
VerticalGrid = IIf ( bi > fvb-7, IIf(frac(bi/2) ==0, screenHigh, screenLow), Null);
Plot (VerticalGrid, "", gridColor, styleStaircase|styleNoLabel|styleNoRescale,0,0, shift);
		
gLine= LineArray( fvb-shift, screenlow, lvb, screenLow, 1, 1);
GridMin = screenLow;
GridMax = screenhigh;
step = round((GridMax - GridMin )/ box);
	
for (m =1; m <step-1 ; m++)
{
	Plot(gLine + m*(Box), "", gridColor, styleLine|styleNoLabel|styleNoRescale, 0, 0 ,shift);
	text = NumToStr( GridMin + m*Box+ 0.5*box, format);
	PlotText(text, (fvb), GridMin + m*Box + 0.16*box, colorWhite);
}	

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
a= 0.4;//(lvb-fvb)/vb;
b=0.4*box;

for(j=fvb+5; j<lvb+1;j++)
{
	
	k=j;
	if(IsNull(ret[j]))
	{
		if(dir[j]==0)
		{
			GfxDrwEll(k,YF[j],a,b);
			for(m=0; m<=n[j]; m++)
			{
				Y[m]=YH[j]-m*box;
				GfxDrwEll(k,Y[m],a,b);
			}
		}
		else
		{
			if(dir[j]==1)
			{
				gfxDrwX(k,YF[j],a,b);
				for(m=0; m<=n[j]; m++)
				{
					Y[m]=YL[j] + m*box;
					gfxDrwX(k,Y[m],a,b);
				}
			}
		}
	}
	else
	{
		if(dir[j]==0)
		{
			gfxDrwX(k,YF[j],a,b);
			for(m=1; m<=n[j]; m++)
			{
				Y[m]=YF[j]-m*box;
				GfxDrwEll(k,Y[m],a,b);
			}
		}	
		else
		{
			if(dir[j]==1)
			{
				
				GfxDrwEll(k,YF[j],a,b);
				for(m=1; m<=n[j]; m++)
				{
					Y[m]=YF[j] + m*box;
					gfxDrwX(k,Y[m],a,b);
				}
			}
		}
	}
}
RequestTimedRefresh( 0.1 );	

I have tried to install the AB 6.22 Beta a few times after downloading a fresh copy. It just hangs for hours at the red “Loading” screen. I am using WIn 10 x64 with 16 GB RAM. The previous AB still works well 6.21.0. Is this perhaps a permissions / administrator issue? Thanks. Steve

I have the same issue. After instaling 6.22, on app launch the welcom popup (Red) comes and at the botton of it , it says “preparing user interface”.

But never enters into the mail app. So i have to downgrade to 6.21 again.

V6.22 uses VC++2017 and new VC++2017 runtimes. There is nothing that should prevent it from “just working”. Out of thousands of installed instances there are few that experience this. One reason can be incompatible 3rd party plugins present in the “Plugins” subfolder. But I know of cases where it happened without 3rd party plugins. The cause is unknown at the moment.

Thanks Neil. V6.22 is still beta so we need to expect a bug or two. Other beta upgrades have been seamless till now.

Steve

It is not a “bug”. At least not anything that I could fix. It is Microsoft-created incompatibility (apparently with Win10) because the very same code works just fine if just compiled with different (older) Microsoft compiler (see 32-bit 6.22).
The quality control at Microsoft went downhill with release of Win10 and entire Win10 is rather in “alpha” stage by my standards. They even broke the USB (normally you won’t see that but in specialist programs that use hardware interfaces like ST-LINK Win10 broke several embedded system development platforms due to breaking changes in USB stack)

1 Like

As I wrote in my original post, 64-bit v6.22 uses new compiler VC++2017 and it is using aggressive optimization for division. It replaces division instruction by multiplication by inverse which executes faster on Intel CPUs. The thing is that although it is mathematically correct, it introduces 1 unit at least significant place difference so if your code relies on that last unit, you are going to get slightly different result. The difference may be later amplified if your code relies on round()/ceil()/floor() the result to integer because if one version produces 0.9999999999999 and the other produces 1.0000000 when you apply floor() function you will get 0 in first case and 1 in second case. Your code does exactly that and that is why you are getting different results. The same things happen when you move floating point code from one CPU architecture to another (like x86 to x64 to ARM)

I could disable all optimizations but then all gains from using newer compiler would be lost. That is not acceptable. So I am trying various workarounds so division accuracy is improved without losing too much speed.

Good news are that in my development version your code runs fine already and produces same chart as 32-bit.

1 Like

Thanks. I removed unused plugins but 6.22 just put them all back again when I tried a fresh install. Also stopped my antivirus checker but it still shows “Preparing user interface”. Should I just leave it for now and wait for 6.23?

Yes, leave it for now as there is nothing you can do on your end.

Great to have such fantastic support. I am trying to get a AB group going in South Africa as I am super enthusiastic about AB and how easy it is to use for a guy with aging brain cells!

Thanks Tomasz, good to here that.

My vote is for pristine math operations versus small speed improvements. I hope you can find a good compromise.

These are not small improvements. We are speaking about 6x faster execution in certain cases.