📄 diffuser.java
字号:
// _current. So we only have to look up the new _next and the new _put. // We'll take advantage of that too. // Last, we'll get rid of the inner for-loop and just hand-code the nine // lookups for the diffuser. // // locals are faster than instance variables // final DoubleGrid2D _valgrid = heatbugs.valgrid; // final double[][] _valgrid_field = heatbugs.valgrid.field; // final double[][] _valgrid2_field = heatbugs.valgrid2.field; // final int _gridWidth = _valgrid.getWidth(); // final int _gridHeight = _valgrid.getHeight(); // final double _evaporationRate = heatbugs.evaporationRate; // final double _diffusionRate = heatbugs.diffusionRate; // double average; // double[] _past = _valgrid_field[_valgrid.stx(-1)]; // double[] _current = _valgrid_field[0]; // double[] _next; // double[] _put; // // for each x and y position // for(int x=0;x< _gridWidth;x++) // { // _next = _valgrid_field[_valgrid.stx(x+1)]; // _put = _valgrid2_field[_valgrid.stx(x)]; // for(int y=0;y< _gridHeight;y++) // { // // for each neighbor of that position // // go across top // average = (_past[_valgrid.sty(y-1)] + _past[_valgrid.sty(y)] + _past[_valgrid.sty(y+1)] + // _current[_valgrid.sty(y-1)] + _current[_valgrid.sty(y)] + _current[_valgrid.sty(y+1)] + // _next[_valgrid.sty(y-1)] + _next[_valgrid.sty(y)] + _next[_valgrid.sty(y+1)]) / 9.0; // // load the new value into HeatBugs.this.valgrid2 // _put[y] = _evaporationRate * // (_current[y] + _diffusionRate * // (average - _current[y])); // } // // swap elements // _past = _current; // _current = _next; // } // ---------------------------------------------------------------------- // Well, that bumped us up a lot! But we can double our speed yet again, // simply by cutting down on the number of times we call sty(). It's called // NINE TIMES for each stx(). Note that we even call _valgrid.sty(y) when // we _know_ that y is always within the toroidal range, that's an easy fix; // just replace _valgrid.sty(y) with y. We can also replace _valgrid.sty(y-1) // and _valgrid.sty(y+1) with variables which we have precomputed so they're not // each recomputed three times (Java's optimizer isn't very smart). Last we // can avoid computing _valgrid.sty(y-1) at all (except once) -- just set it // to whatever y was last time. // // The resultant code is below. We could speed this up a bit more, avoiding // calls to sty(y+1) and reducing unnecessary calls to stx, but it won't buy // us the giant leaps we're used to by now. // locals are faster than instance variables final DoubleGrid2D _valgrid = heatbugs.valgrid; final double[][] _valgrid_field = heatbugs.valgrid.field; final double[][] _valgrid2_field = heatbugs.valgrid2.field; final int _gridWidth = _valgrid.getWidth(); final int _gridHeight = _valgrid.getHeight(); final double _evaporationRate = heatbugs.evaporationRate; final double _diffusionRate = heatbugs.diffusionRate; double average; double[] _past = _valgrid_field[_valgrid.stx(-1)]; double[] _current = _valgrid_field[0]; double[] _next; double[] _put; int yminus1; int yplus1; // for each x and y position for(int x=0;x< _gridWidth;x++) { _next = _valgrid_field[_valgrid.stx(x+1)]; _put = _valgrid2_field[_valgrid.stx(x)]; yminus1 = _valgrid.sty(-1); // initialized for(int y=0;y< _gridHeight;y++) { // for each neighbor of that position // go across top yplus1 = _valgrid.sty(y+1); average = (_past[yminus1] + _past[y] + _past[yplus1] + _current[yminus1] + _current[y] + _current[yplus1] + _next[yminus1] + _next[y] + _next[yplus1]) / 9.0; // load the new value into HeatBugs.this.valgrid2 _put[y] = _evaporationRate * (_current[y] + _diffusionRate * (average - _current[y])); // set y-1 to what y was "last time around" yminus1 = y; } // swap elements _past = _current; _current = _next; } // ---------------------------------------------------------------------- // If you have a multiprocessor machine, you can speed this up further by // dividing the work among two processors. We do that over in ThreadedDiffuser.java // // You can also avoid some of the array bounds checks by using linearized // double arrays -- that is, using a single array but computing the double // array location yourself. That way you only have one bounds check instead // of two. This is how, for example, Repast does it. This is certainly a // little faster than two checks. We use a two-dimensional array because a // linearized array class is just too cumbersome to use in Java right now, // what with all the get(x,y) and set(x,y,v) instead of just saying foo[x][y]. // Plus it turns out that for SMALL (say 100x100) arrays, the double array is // actually *faster* because of cache advantages. // // At some point in the future Java's going to have to fix the lack of true // multidimensional arrays. It's a significant speed loss. IBM has some proposals // in the works but it's taking time. However their proposals are for array classes. // So allow me to suggest how we can do a little syntactic sugar to make that prettier. // The array syntax for multidimensional arrays should be foo[x,y,z] and for // standard Java arrays it should be foo[x][y][z]. This allows us to mix the two: // a multidimensional array of Java arrays for example: foo[x,y][z]. Further we // should be allowed to linearize a multidimensional array, accessing all the elements // in row-major order. The syntax for a linearized array simply has empty commas: // foo[x,,] // oh yeah, we have one last step. // now finally copy HeatBugs.this.valgrid2 to HeatBugs.this.valgrid, and we're done _valgrid.setTo(heatbugs.valgrid2); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -