Iterative Calculation

Iterative calculations can help with finding solutions to certain calculations by running them over and over using the previous result. You can also perform what-if analysis with the CalcEngine.goalSeek function, which uses iterative calculations in SpreadJS.

Users can enable/disable iterative calculation in the workbook options. When iterative calculation is disabled, all the circular referenced cells will have 0 for the value, and the other cells referencing them will be 0. When iterative calculation is enabled, all the circular references will calculate iteratively until all the value changes are smaller than the iterativeCalculationMaximumChange or the iteratation count is iterativeCalculationMaximumIterations. API is as follows: iterativeCalculation: Enable or Disable the Iterative Calculation iterativeCalculationMaximumIterations: The Maximum Iterations when Iterative Calculation, default value is 1000, value range is 1~32767 iterativeCalculationMaximumChange: The Maximum Change when Iterative Calculation, default 0.01, value range is 0~MaxDouble(1.79769313486232e308) The isCircularReference property is added for the Events.UserFormulaEntered, it will be true if user entered a circular reference. For example: You can get all the circular references in the workbook by function getCircularReference. For example:
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(_getElementById("ss")); initSpread(spread); }; function initSpread(spread) { var sheet = spread.getActiveSheet(); spread.suspendPaint(); spread.suspendCalcService(); sheet.setColumnWidth(0, 120); sheet.setColumnWidth(1, 100); sheet.setColumnWidth(2, 120); sheet.setColumnWidth(4, 120); sheet.setColumnWidth(5, 130); sheet.getCell(1, 1).foreColor("blue"); sheet.getCell(5, 1).foreColor("blue"); sheet.getCell(9, 1).foreColor("blue").formatter("0.0%"); sheet.getRange(1, 1, 7, 1).formatter("0.0"); sheet.setFormula(6, 5, '=F7+1'); sheet.setValue(0, 0, "Details"); sheet.setValue(1, 0, "Cash Revenue"); sheet.setValue(2, 0, "Interest Expense"); sheet.setValue(3, 0, "Cash Profit"); sheet.setValue(5, 0, "Beginning Debt"); sheet.setValue(6, 0, "Ending Debt"); sheet.setValue(7, 0, "Average Debt"); sheet.setValue(9, 0, "Interest"); sheet.setValue(0, 1, "Amount"); sheet.setValue(1, 1, 100); sheet.setFormula(2, 1, '=B10*B8'); sheet.setFormula(3, 1, '=B2-B3'); sheet.setValue(5, 1, 150); sheet.setFormula(6, 1, '=B6-B4'); sheet.setFormula(7, 1, '=AVERAGE(B6:B7)'); sheet.setValue(9, 1, 0.05); sheet.setValue(0, 2, "Formula") sheet.setFormula(2, 2, '=FORMULATEXT(B3)'); sheet.setFormula(3, 2, '=FORMULATEXT(B4)'); sheet.setFormula(6, 2, '=FORMULATEXT(B7)'); sheet.setFormula(7, 2, '=FORMULATEXT(B8)'); sheet.getRange(0, 0, 1, 3).backColor("#f2f2f2").foreColor("black"); sheet.getRange(6, 5, 1, 1).backColor("#009e00").foreColor("white"); sheet.getRange(1, 4, 1, 2).backColor("#f2f2f2").foreColor("black"); sheet.getRange(1, 0, 9, 3).setBorder(new GC.Spread.Sheets.LineBorder("#f2f2f2", GC.Spread.Sheets.LineStyle.thin), {all: true}); sheet.getRange(2, 4, 3, 2).setBorder(new GC.Spread.Sheets.LineBorder("#f2f2f2", GC.Spread.Sheets.LineStyle.thin), {all: true}); sheet.setValue(1, 4, "Use the Leibniz formula to approximate π") sheet.setValue(2, 4, "n: 1→∞") sheet.setValue(3, 4, {"richText":[{"text":"Pn: 4*(-1)"},{"style":{"vertAlign":1},"text":"n+1"},{"text":"/(2n-1)"}],"text":"Pn=4*(-1)n+1/(2n-1)"}); sheet.setValue(4, 4, "π: P1+P2+P3+...+Pn") sheet.setFormula(4, 5, '=IFERROR(F4,0)+F5'); sheet.setFormula(3, 5, '=IF(F3<1,0,4/(2*F3-1)*POWER(-1,F3+1))'); sheet.setFormula(2, 5, '=F3+1'); // set the n in the last to make sure that added from n=1 spread.resumeCalcService(); spread.resumePaint(); bindEvent(spread); } function bindEvent (spread) { _getElementById("IterativeCalculation").addEventListener('change', function () { spread.options.iterativeCalculation = this.checked; }); _getElementById("MaximumIterations").addEventListener('change', function () { spread.options.iterativeCalculationMaximumIterations = this.value; }); _getElementById("MaximumChange").addEventListener('change', function () { spread.options.iterativeCalculationMaximumChange = this.value; }); _getElementById("RecalcAll").addEventListener('click', function () { spread.getActiveSheet().recalcAll(true); }); } function _getElementById(id) { return document.getElementById(id); }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"></div> <div class="options-container"> <label>Change the <b>Maximum Iterations</b> and <b>Maximum Change</b> options below then press <b>Recalculate</b> to see how this affects the calculations in cell F7.</label> <div class="option-row"> <input style="width: 20px;float: left;" type="checkbox" id="IterativeCalculation" checked="checked"/> <label for="IterativeCalculation">Iterative Calculation</label> </div> <div class="option-row"> <label for="MaximumIterations">Maximum Iterations:</label> <input type="number" id="MaximumIterations" value="1000"> </div> <div class="option-row"> <label for="MaximumChange">Maximum Change:</label> <input type="number" id="MaximumChange" value="0.01"> </div> <div class="option-row"> <button id="RecalcAll">Recalculate</button> </div> </div> </div></body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 10px; } input { margin-bottom: 5px; padding: 2px 4px; width: 100%; box-sizing: border-box; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }