The task was to implement an algorithm for solving a given system of nonlinear equations by the Newton method. The essence of the algorithm in the cyclic calculation of floating-point numbers. When I started testing the program on different devices for the sake of interest, I got a strange result. To obtain the final result, different devices require a different number of cycles, despite the same input data and result. Here is what the devices showed (invariably at each launch):

  • Meizu M2 Note (MT6753 8 * 1.3Ghz Cortex A53, 64bit): 229 cycles;
  • ASUS Zenfon 5 (Intel Atom Z2560 2 * 1.6Ghz x86): 145 cycles;
  • Lenovo A850 + (MT6592): 149 cycles;
  • Samsung Galaxy A3 (Qualcomm Snapdragon 410 4 * 1.2Ghz Cortex A53 64bit): 1878 cycles.

I also noticed that the number of cycles for all devices with qualcomm snapdragon is the same: 1878. Algorithm code:

ArrayList<Box> box = new ArrayList<Box>(); MyAdapter adapter; ListView listView; double precision = 1E-28; double K1F1, K2F1, K3F1, K4F1, K1F2, K2F2, K3F2, K4F2, K1F3, K2F3, K3F3; int flag=0; //ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Π²Ρ‹Ρ‚Π°Ρ‰ΠΈΠ» ΠΈΠ· ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° ΠΊΠ½ΠΎΠΏΠΊΠΈ, ΠΎΠ½ сам Π½Π΅ Π²Π°ΠΆΠ΅Π½. А эти ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Π² countFx() ΠΈ countWx() K1F1=16d; K2F1=16d; K3F1=1d; K4F1=16d; K1F2=1d; K2F2=1d; K3F2=1d; K4F2=3d; K1F3=1d; K2F3=1d; K3F3=0d; private double[] Countfx(double[] x){//Π²Π΅ΠΊΡ‚ΠΎΡ€ Fx double[] fx = new double[3]; fx[0] = K1F1*Math.pow(x[0],4)+K2F1*Math.pow(x[1],4)+K3F1*Math.pow(x[2],4)-K4F1; fx[1] = K1F2*Math.pow(x[0],2)+K2F2*Math.pow(x[1],2)+K3F2*Math.pow(x[2],2)-K4F2; fx[2] = K1F3*Math.pow(x[0],3)-K2F3*x[1]-K3F3; return fx; } private double Countdet(double[][] ar){//ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ 3*3 double detar; detar = ar[0][0]*ar[1][1]*ar[2][2] + ar[0][1]*ar[1][2]*ar[2][0] + ar[0][2]*ar[1][0]*ar[2][1] - ar[2][0]*ar[1][1]*ar[0][2] - ar[2][1]*ar[1][2]*ar[0][0] - ar[2][2]*ar[1][0]*ar[0][1]; return detar; } private double[][] CountWx(double[] x){//ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Π° якоби double[][] Wx = new double[3][3]; Wx[0][0] = K1F1*4d*Math.pow(x[0],3); Wx[1][0] = K2F1*4d*Math.pow(x[1],3); Wx[2][0] = K3F1*4d*Math.pow(x[2],3); Wx[0][1] = K1F2*2d*x[0]; Wx[1][1] = K2F2*2d*x[1]; Wx[2][1] = K3F2*2d*x[2]; Wx[0][2] = K1F3*3d*Math.pow(x[0],2); Wx[1][2] = K2F3*x[1]; Wx[2][2] = 0; return Wx; } private double[][] CountMinorMatrix(double[][] matrix){//ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Π° ΠΌΠΈΠ½ΠΎΡ€ΠΎΠ² (для нахоТдСния ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹) double[][] minor = new double[3][3]; minor[0][0] = matrix[1][1]*matrix[2][2]-(matrix[1][2]*matrix[2][1]); minor[1][0] = matrix[0][1]*matrix[2][2]-(matrix[0][2]*matrix[2][1]); minor[2][0] = matrix[0][1]*matrix[1][2]-(matrix[1][1]*matrix[0][2]); minor[0][1] = matrix[1][0]*matrix[2][2]-(matrix[1][2]*matrix[2][0]); minor[1][1] = matrix[0][0]*matrix[2][2]-(matrix[0][2]*matrix[2][0]); minor[2][1] = matrix[0][0]*matrix[1][2]-(matrix[1][0]*matrix[0][2]); minor[0][2] = matrix[1][0]*matrix[2][1]-(matrix[1][1]*matrix[2][0]); minor[1][2] = matrix[0][0]*matrix[2][1]-(matrix[0][1]*matrix[2][0]); minor[2][2] = matrix[0][0]*matrix[1][1]-(matrix[0][1]*matrix[1][0]); return minor; } private double[][] getTransposedMatrix(double[][] matrix){//транспонированиС ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ double[][] tr = new double[3][3]; for(int i=0; i<3; i++){ for(int j=0; j<3; j++){ tr[i][j]=matrix[j][i]; } } return tr; } private double[][] MultiplyMatrixAtNumber(double[][] m, double num){//ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ 3*3 Π½Π° число for(int i=0; i<3; i++){ for(int j=0; j<3; j++){ m[i][j]*=num; } } return m; } private double[][] getInverseMatrix(double[][] m){//Π½Π°Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ double det = Countdet(m); m=CountMinorMatrix(m); if(m[1][0]>0) m[1][0]=-Math.abs(m[1][0]); else m[1][0]=Math.abs(m[1][0]); if(m[0][1]>0) m[0][1]=-Math.abs(m[0][1]); else m[0][1]=Math.abs(m[0][1]); if(m[2][1]>0) m[2][1]=-Math.abs(m[2][1]); else m[2][1]=Math.abs(m[2][1]); if(m[1][2]>0) m[1][2]=-Math.abs(m[1][2]); else m[1][2]=Math.abs(m[1][2]); m=getTransposedMatrix(m); det = 1d/det; m=MultiplyMatrixAtNumber(m,det); return m; } private double[] MultiplyMatrix(double[][] m1, double[] m2){//ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ 3*3 ΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° 1*3 double[] res = new double[3]; for(int i=0; i<3; i++) res[i]=0; for(int j=0; j<3; j++){ for(int i=0; i<3; i++){ res[j]+=m1[i][j]*m2[i]; } } return res; } private double[] CountDifMatrix(double[] m1, double[] m2){//Ρ€Π°Π·Π½ΠΎΡΡ‚ΡŒ ΠΌΠ°Ρ‚Ρ€ΠΈΡ† double[] sum = new double[3]; for(int i=0; i<3; i++){ sum[i] = m1[i]-m2[i]; } return sum; } private boolean compare(double[] m1, double[] m2){//сравнСниС Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΎΠ² int n=0; for(int i=0; i<3; i++){ if(m1[i]==m2[i]) n++; } if(n>=2) return true; else return false; } private void CountFunction(){ double[] X0={1d,1d,1d}; double[] Fx; double[][] Wx; double det; double[][] WxInverse; double[] multRes; double[] result; int w=0, it=0, col=0; while(w==0 && col<1){ Fx=Countfx(X0);//Π½Π°Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° Fx Wx=CountWx(X0);//Π½Π°Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ якоби det=Countdet(Wx);//Π½Π°Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ опрСдСлитСля ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π° 0 if(det==0){ break; } WxInverse=getInverseMatrix(Wx);//Π½Π°Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ multRes=MultiplyMatrix(WxInverse,Fx); result=CountDifMatrix(X0,multRes); Box b=new Box(result);//ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ просто Ρ…Ρ€Π°Π½ΠΈΡ‚ массив (для ArrayList Π½ΡƒΠΆΠ΅Π½ абстрактный Ρ‚ΠΈΠΏ) outputNumbersinLog(result);//Π»ΠΎΠ³ box.add(b);// запись Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° Ρ†ΠΈΠΊΠ»Π° Π² arraylist boolean compare=compare(X0,result);//сравнСниС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΈ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ Ρ†ΠΈΠΊΠ»ΠΎΠ² if(compare) col++; for(int i=0; i<3; i++){ if(Math.abs(result[i])<precision){ w=1; } } X0=result;//Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Ρ†ΠΈΠΊΠ»Π° становится Π²Ρ…ΠΎΠ΄Π½Ρ‹ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ для ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ it++; } Log.d("function","Π˜Ρ‚Π΅Ρ€Π°Ρ†ΠΈΠΉ: "+it); Box out = box.get(it-1); //Π²Ρ‹Π²ΠΎΠ΄ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° Π² TextView ((TextView)findViewById(R.id.X)).setText("X = "+out.s[0]); ((TextView)findViewById(R.id.Y)).setText("Y = "+out.s[1]); ((TextView)findViewById(R.id.Z)).setText("Z = "+out.s[2]); } 
  • and you can attach the code? And what is your error? The internal implementations of some operations may be critical (for example, the accuracy may depend on the platform capacity and so on). Whether types are used in the code without a hard specification (int - 4 bytes can be both 8 and 2 at one time). - pavel
  • this should not be, you may be using some specific code, or merge the cycles incorrectly - Vladyslav Matviienko
  • In all calculations, numbers are reduced to double (except for counters, and so on, of course). Of course, I can provide the code, but it is long, the result itself is correct (for verification, the result is given in the problem statement). The code was written using this algorithm: exponenta.ru/educat/systemat/hanova/equation/loc.asp (the equation itself is different) - Mikhail Vilisov
  • if the code is in java, you can try strictfp class / methods with the strictfp modifier. - zRrr 2:26 pm
  • strictfp for android development consider, sort of like, unnecessary. At least this is the way most of the manual sites write, for example: developer.alexanderklimov.ru/android/java/strictfp.php - Mikhail Vilisov

1 answer 1

In order to guarantee the correctness of the calculations, two things are necessary.

First, it is necessary to mark the classes involved in computing with the strictfp modifier. (This is noted by @zRrr in the comment .) Without this, floating-point calculations are performed in an optimal way for the current processor, with possible loss of accuracy.

Secondly, it is necessary to use StrictMath instead of the Math class, which performs calculations in FP-strict mode.

  • Now there is another interesting point: with StrictMath, the application refused to work on devices with intel atom. But this is probably another story altogether ... - Mikhail Vilisov
  • Wow, strange. But if you only use StrictMath for exponentiation, you can rewrite it manually. - VladD
  • It turns out that there was just an error when building or installing Glitched Wednesday. Everything works everywhere. - Michael Vilisov
  • @ MihailVilisov: Ah, well, that's great, that figured out. - VladD