Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <sal/config.h>
11 :
12 : #include <algorithm>
13 : #include <cmath>
14 :
15 : #include "calcconfig.hxx"
16 : #include "calcoptionsdlg.hxx"
17 : #include "docfunc.hxx"
18 : #include "docsh.hxx"
19 : #include "interpre.hxx"
20 : #include "sc.hrc"
21 : #include "scresid.hxx"
22 : #include "scopetools.hxx"
23 : #include "viewdata.hxx"
24 :
25 : #include <com/sun/star/frame/Desktop.hpp>
26 : #include <com/sun/star/frame/XDesktop2.hpp>
27 :
28 : #include <comphelper/random.hxx>
29 : #include <svtools/svlbitm.hxx>
30 : #include <svtools/treelistentry.hxx>
31 :
32 : #if HAVE_FEATURE_OPENCL
33 : #include "formulagroup.hxx"
34 : #include "globalnames.hxx"
35 : #endif
36 :
37 : namespace {
38 :
39 0 : formula::FormulaGrammar::AddressConvention toAddressConvention(sal_Int32 nPos)
40 : {
41 0 : switch (nPos)
42 : {
43 : case 1:
44 0 : return formula::FormulaGrammar::CONV_OOO;
45 : case 2:
46 0 : return formula::FormulaGrammar::CONV_XL_A1;
47 : case 3:
48 0 : return formula::FormulaGrammar::CONV_XL_R1C1;
49 : case 0:
50 : default:
51 : ;
52 : }
53 :
54 0 : return formula::FormulaGrammar::CONV_UNSPECIFIED;
55 : }
56 :
57 : }
58 :
59 0 : ScCalcOptionsDialog::ScCalcOptionsDialog(vcl::Window* pParent, const ScCalcConfig& rConfig)
60 : : ModalDialog(pParent, "FormulaCalculationOptions",
61 : "modules/scalc/ui/formulacalculationoptions.ui")
62 : , maConfig(rConfig)
63 0 : , mbSelectedEmptyStringAsZero(rConfig.mbEmptyStringAsZero)
64 : {
65 0 : get(mpTestButton, "test");
66 0 : get(mpOpenclInfoList, "opencl_list");
67 0 : get(mpBtnAutomaticSelectionTrue, "automatic_select_true");
68 0 : get(mpBtnAutomaticSelectionFalse, "automatic_select_false");
69 0 : get(mpFtFrequency, "frequency");
70 0 : get(mpFtComputeUnits, "compute_units");
71 0 : get(mpFtMemory, "memory");
72 :
73 0 : get(mpConversion,"comboConversion");
74 0 : mpConversion->SelectEntryPos(static_cast<sal_Int32>(rConfig.meStringConversion), true);
75 0 : mpConversion->SetSelectHdl(LINK(this, ScCalcOptionsDialog, ConversionModifiedHdl));
76 :
77 0 : get(mpEmptyAsZero,"checkEmptyAsZero");
78 0 : mpEmptyAsZero->Check(rConfig.mbEmptyStringAsZero);
79 0 : mpEmptyAsZero->SetClickHdl(LINK(this, ScCalcOptionsDialog, AsZeroModifiedHdl));
80 :
81 0 : get(mpSyntax,"comboSyntaxRef");
82 0 : mpSyntax->SelectEntryPos(rConfig.meStringRefAddressSyntax);
83 0 : mpSyntax->SetSelectHdl(LINK(this, ScCalcOptionsDialog, SyntaxModifiedHdl));
84 :
85 0 : get(mpUseOpenCL,"CBUseOpenCL");
86 0 : mpUseOpenCL->Check(rConfig.mbOpenCLSubsetOnly);
87 0 : mpUseOpenCL->SetClickHdl(LINK(this, ScCalcOptionsDialog, CBUseOpenCLHdl));
88 :
89 0 : get(mpSpinButton,"spinOpenCLSize");
90 0 : mpSpinButton->SetValue(rConfig.mnOpenCLMinimumFormulaGroupSize);
91 0 : mpSpinButton->SetModifyHdl(LINK(this, ScCalcOptionsDialog, SpinOpenCLMinSizeHdl));
92 :
93 0 : get(mpEditField, "entry");
94 0 : mpEditField->SetText(ScOpCodeSetToSymbolicString(maConfig.maOpenCLSubsetOpCodes));
95 0 : mpEditField->set_height_request(4 * mpEditField->GetTextHeight());
96 :
97 0 : mpEditField->SetModifyHdl(LINK(this, ScCalcOptionsDialog, EditModifiedHdl));
98 :
99 0 : mpOpenclInfoList->set_height_request(4* mpOpenclInfoList->GetTextHeight());
100 0 : mpOpenclInfoList->SetStyle(mpOpenclInfoList->GetStyle() | WB_CLIPCHILDREN | WB_FORCE_MAKEVISIBLE);
101 0 : mpOpenclInfoList->SetHighlightRange();
102 0 : mpOpenclInfoList->GetParent()->Hide();
103 0 : mpOpenclInfoList->SetSelectHdl(LINK(this, ScCalcOptionsDialog, DeviceSelHdl));
104 :
105 0 : mpBtnAutomaticSelectionTrue->SetToggleHdl(LINK(this, ScCalcOptionsDialog, BtnAutomaticSelectHdl));
106 :
107 0 : maSoftware = get<vcl::Window>("software")->GetText();
108 :
109 0 : mpTestButton->SetClickHdl(LINK(this, ScCalcOptionsDialog, TestClickHdl));
110 0 : }
111 :
112 0 : ScCalcOptionsDialog::~ScCalcOptionsDialog()
113 : {
114 0 : disposeOnce();
115 0 : }
116 :
117 0 : void ScCalcOptionsDialog::dispose()
118 : {
119 0 : mpUseOpenCL.clear();
120 0 : mpSpinButton.clear();
121 0 : mpEditField.clear();
122 0 : mpTestButton.clear();
123 0 : mpFtFrequency.clear();
124 0 : mpFtComputeUnits.clear();
125 0 : mpFtMemory.clear();
126 0 : mpOpenclInfoList.clear();
127 0 : mpBtnAutomaticSelectionTrue.clear();
128 0 : mpBtnAutomaticSelectionFalse.clear();
129 0 : ModalDialog::dispose();
130 0 : }
131 :
132 0 : void ScCalcOptionsDialog::OpenCLAutomaticSelectionChanged()
133 : {
134 0 : bool bValue = mpBtnAutomaticSelectionTrue->IsChecked();
135 0 : if(bValue)
136 0 : mpOpenclInfoList->Disable();
137 : else
138 0 : mpOpenclInfoList->Enable();
139 :
140 0 : maConfig.mbOpenCLAutoSelect = bValue;
141 0 : }
142 :
143 0 : void ScCalcOptionsDialog::SelectedDeviceChanged()
144 : {
145 : #if HAVE_FEATURE_OPENCL
146 0 : SvTreeListEntry* pEntry = mpOpenclInfoList->GetModel()->GetView(0)->FirstSelected();
147 0 : if(!pEntry)
148 0 : return;
149 :
150 0 : OpenCLDeviceInfo* pInfo = static_cast<OpenCLDeviceInfo*>(pEntry->GetUserData());
151 0 : if(pInfo)
152 : {
153 0 : mpFtFrequency->SetText(OUString::number(pInfo->mnFrequency));
154 0 : mpFtComputeUnits->SetText(OUString::number(pInfo->mnComputeUnits));
155 0 : mpFtMemory->SetText(OUString::number(pInfo->mnMemory/1024/1024));
156 : }
157 : else
158 : {
159 0 : mpFtFrequency->SetText(OUString());
160 0 : mpFtComputeUnits->SetText(OUString());
161 0 : mpFtMemory->SetText(OUString());
162 : }
163 :
164 0 : SvLBoxString* pBoxEntry = dynamic_cast<SvLBoxString*>(pEntry->GetItem(1));
165 0 : if (!pBoxEntry)
166 0 : return;
167 :
168 0 : OUString aDevice = pBoxEntry->GetText();
169 : // use english string for configuration
170 0 : if(aDevice == maSoftware)
171 0 : aDevice = OPENCL_SOFTWARE_DEVICE_CONFIG_NAME;
172 :
173 0 : maConfig.maOpenCLDevice = aDevice;
174 : #endif
175 : }
176 :
177 0 : IMPL_LINK(ScCalcOptionsDialog, AsZeroModifiedHdl, CheckBox*, pCheckBox )
178 : {
179 0 : maConfig.mbEmptyStringAsZero = pCheckBox->IsChecked();
180 0 : return 0;
181 : }
182 :
183 0 : IMPL_LINK(ScCalcOptionsDialog, ConversionModifiedHdl, ListBox*, pConv )
184 : {
185 :
186 0 : maConfig.meStringConversion = (ScCalcConfig::StringConversion)pConv->GetSelectEntryPos();
187 0 : switch (maConfig.meStringConversion)
188 : {
189 : case ScCalcConfig::StringConversion::ILLEGAL:
190 0 : maConfig.mbEmptyStringAsZero = false;
191 0 : mpEmptyAsZero->Check(false);
192 0 : mpEmptyAsZero->Enable(false);
193 0 : break;
194 : case ScCalcConfig::StringConversion::ZERO:
195 0 : maConfig.mbEmptyStringAsZero = true;
196 0 : mpEmptyAsZero->Check(true);
197 0 : mpEmptyAsZero->Enable(false);
198 0 : break;
199 : case ScCalcConfig::StringConversion::UNAMBIGUOUS:
200 : case ScCalcConfig::StringConversion::LOCALE:
201 : // Reset to the value the user selected before.
202 0 : maConfig.mbEmptyStringAsZero = mbSelectedEmptyStringAsZero;
203 0 : mpEmptyAsZero->Enable(true);
204 0 : break;
205 : }
206 0 : return 0;
207 : }
208 :
209 0 : IMPL_LINK(ScCalcOptionsDialog, SyntaxModifiedHdl, ListBox*, pSyntax)
210 : {
211 0 : maConfig.meStringRefAddressSyntax = toAddressConvention(pSyntax->GetSelectEntryPos());
212 0 : return 0;
213 : }
214 :
215 0 : IMPL_LINK(ScCalcOptionsDialog, CBUseOpenCLHdl, CheckBox*, pCheckBox)
216 : {
217 0 : maConfig.mbOpenCLSubsetOnly = pCheckBox->IsChecked();
218 0 : return 0;
219 : }
220 :
221 0 : IMPL_LINK(ScCalcOptionsDialog, SpinOpenCLMinSizeHdl, NumericField*, pSpin)
222 : {
223 0 : maConfig.mnOpenCLMinimumFormulaGroupSize = pSpin->GetValue();
224 0 : return 0;
225 : }
226 :
227 0 : IMPL_LINK_NOARG(ScCalcOptionsDialog, BtnAutomaticSelectHdl)
228 : {
229 0 : OpenCLAutomaticSelectionChanged();
230 0 : return 0;
231 : }
232 :
233 0 : IMPL_LINK_NOARG(ScCalcOptionsDialog, DeviceSelHdl)
234 : {
235 0 : SelectedDeviceChanged();
236 0 : return 0;
237 : }
238 :
239 0 : IMPL_LINK(ScCalcOptionsDialog, EditModifiedHdl, Edit*, pCtrl)
240 : {
241 0 : maConfig.maOpenCLSubsetOpCodes = ScStringToOpCodeSet(pCtrl->GetText());
242 0 : return 0;
243 : }
244 :
245 : namespace {
246 :
247 : struct Area
248 : {
249 : OUString msTitle;
250 : int mnRows;
251 :
252 0 : Area(const OUString& rTitle, int nRows = ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize + 2) :
253 : msTitle(rTitle),
254 0 : mnRows(nRows)
255 : {
256 0 : }
257 :
258 0 : virtual ~Area()
259 0 : {
260 0 : }
261 :
262 : virtual void addHeader(ScDocument *pDoc, int nTab) const = 0;
263 :
264 : virtual void addRow(ScDocument *pDoc, int nRow, int nTab) const = 0;
265 :
266 : virtual OUString getSummaryFormula(ScDocument *pDoc, int nTab) const = 0;
267 : };
268 :
269 0 : struct OpenCLTester
270 : {
271 : int mnTestAreas;
272 : ScDocShell* mpDocShell;
273 : ScDocument *mpDoc;
274 : bool mbOldAutoCalc;
275 : ScCalcConfig maOldCalcConfig;
276 :
277 0 : OpenCLTester() :
278 0 : mnTestAreas(0)
279 : {
280 0 : css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
281 0 : css::uno::Reference< css::frame::XDesktop2 > xComponentLoader = css::frame::Desktop::create(xContext);
282 : css::uno::Reference< css::lang::XComponent >
283 0 : xComponent( xComponentLoader->loadComponentFromURL( "private:factory/scalc",
284 : "_blank", 0,
285 0 : css::uno::Sequence < css::beans::PropertyValue >() ) );
286 0 : mpDocShell = dynamic_cast<ScDocShell*>(SfxObjectShell::GetShellFromComponent(xComponent));
287 :
288 : assert(mpDocShell);
289 :
290 0 : mpDoc = &mpDocShell->GetDocument();
291 :
292 0 : mbOldAutoCalc = mpDoc->GetAutoCalc();
293 0 : mpDoc->SetAutoCalc(false);
294 0 : maOldCalcConfig = ScInterpreter::GetGlobalConfig();
295 0 : ScCalcConfig aConfig(maOldCalcConfig);
296 0 : aConfig.mnOpenCLMinimumFormulaGroupSize = 20;
297 0 : ScInterpreter::SetGlobalConfig(aConfig);
298 :
299 0 : mpDoc->SetString(ScAddress(0,0,0), "Result:");
300 0 : }
301 :
302 0 : void addTest(const Area &rArea)
303 : {
304 0 : mnTestAreas++;
305 0 : (void) mpDocShell->GetDocFunc().InsertTable(mnTestAreas, rArea.msTitle, false, true);
306 :
307 0 : rArea.addHeader(mpDoc, mnTestAreas);
308 :
309 0 : for (int i = 0; i < rArea.mnRows; ++i)
310 0 : rArea.addRow(mpDoc, i, mnTestAreas);
311 :
312 0 : mpDoc->SetString(ScAddress(0,1+mnTestAreas-1,0), rArea.msTitle + ":");
313 0 : mpDoc->SetString(ScAddress(1,1+mnTestAreas-1,0), rArea.getSummaryFormula(mpDoc, mnTestAreas));
314 :
315 : mpDoc->SetString(ScAddress(1,0,0),
316 0 : "=IF(SUM(" +
317 : ScRange(ScAddress(1,1,0),
318 0 : ScAddress(1,1+mnTestAreas-1,0)).Format(SCA_VALID|SCA_VALID_COL|SCA_VALID_ROW) +
319 0 : ")=0,\"PASS\",\"FAIL\")");
320 0 : }
321 : };
322 :
323 : struct Op : Area
324 : {
325 : OUString msOp;
326 : double mnRangeLo;
327 : double mnRangeHi;
328 : double mnEpsilon;
329 :
330 0 : Op(const OUString& rTitle,
331 : const OUString& rOp,
332 : double nRangeLo, double nRangeHi,
333 : double nEpsilon) :
334 : Area(rTitle),
335 : msOp(rOp),
336 : mnRangeLo(nRangeLo),
337 : mnRangeHi(nRangeHi),
338 0 : mnEpsilon(nEpsilon)
339 : {
340 0 : }
341 :
342 0 : virtual ~Op()
343 0 : {
344 0 : }
345 : };
346 :
347 : struct UnOp : Op
348 : {
349 : double (*mpFun)(double nArg);
350 : bool (*mpFilterOut)(double nArg);
351 :
352 0 : UnOp(const OUString& rTitle,
353 : const OUString& rOp,
354 : double nRangeLo, double nRangeHi,
355 : double nEpsilon,
356 : double (*pFun)(double nArg),
357 : bool (*pFilterOut)(double nArg) = nullptr) :
358 : Op(rTitle, rOp, nRangeLo, nRangeHi, nEpsilon),
359 : mpFun(pFun),
360 0 : mpFilterOut(pFilterOut)
361 : {
362 0 : }
363 :
364 0 : virtual ~UnOp()
365 0 : {
366 0 : }
367 :
368 0 : virtual void addHeader(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
369 : {
370 0 : pDoc->SetString(ScAddress(0,0,nTab), "arg");
371 0 : pDoc->SetString(ScAddress(1,0,nTab), msOp + "(arg)");
372 0 : pDoc->SetString(ScAddress(2,0,nTab), "expected");
373 0 : }
374 :
375 0 : virtual void addRow(ScDocument *pDoc, int nRow, int nTab) const SAL_OVERRIDE
376 : {
377 : double nArg;
378 :
379 0 : do {
380 0 : nArg = comphelper::rng::uniform_real_distribution(mnRangeLo, mnRangeHi);
381 0 : } while (mpFilterOut != nullptr && mpFilterOut(nArg));
382 :
383 0 : pDoc->SetValue(ScAddress(0,1+nRow,nTab), nArg);
384 :
385 : pDoc->SetString(ScAddress(1,1+nRow,nTab),
386 0 : "=" + msOp + "(" + ScAddress(0,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) + ")");
387 :
388 0 : pDoc->SetValue(ScAddress(2,1+nRow,nTab), mpFun(nArg));
389 :
390 0 : if (mnEpsilon < 0)
391 : {
392 : // relative epsilon
393 : pDoc->SetString(ScAddress(3,1+nRow,nTab),
394 0 : "=IF(ABS((" + ScAddress(1,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
395 0 : "-" + ScAddress(2,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
396 0 : ")/" + ScAddress(2,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
397 0 : ")<=" + OUString::number(-mnEpsilon) +
398 0 : ",0,1)");
399 : }
400 : else
401 : {
402 : // absolute epsilon
403 : pDoc->SetString(ScAddress(3,1+nRow,nTab),
404 0 : "=IF(ABS(" + ScAddress(1,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
405 0 : "-" + ScAddress(2,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
406 0 : ")<=" + OUString::number(mnEpsilon) +
407 0 : ",0,1)");
408 : }
409 0 : }
410 :
411 0 : virtual OUString getSummaryFormula(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
412 : {
413 0 : return "=SUM(" +
414 : ScRange(ScAddress(3,1,nTab),
415 0 : ScAddress(3,1+mnRows-1,nTab)).Format(SCA_VALID|SCA_TAB_3D|SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB, pDoc) +
416 0 : ")";
417 : }
418 : };
419 :
420 : struct BinOp : Op
421 : {
422 : double (*mpFun)(double nLhs, double nRhs);
423 : bool (*mpFilterOut)(double nLhs, double nRhs);
424 :
425 0 : BinOp(const OUString& rTitle,
426 : const OUString& rOp,
427 : double nRangeLo, double nRangeHi,
428 : double nEpsilon,
429 : double (*pFun)(double nLhs, double nRhs),
430 : bool (*pFilterOut)(double nLhs, double nRhs) = nullptr) :
431 : Op(rTitle, rOp, nRangeLo, nRangeHi, nEpsilon),
432 : mpFun(pFun),
433 0 : mpFilterOut(pFilterOut)
434 : {
435 0 : }
436 :
437 0 : virtual ~BinOp()
438 0 : {
439 0 : }
440 :
441 0 : virtual void addHeader(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
442 : {
443 0 : pDoc->SetString(ScAddress(0,0,nTab), "lhs");
444 0 : pDoc->SetString(ScAddress(1,0,nTab), "rhs");
445 0 : pDoc->SetString(ScAddress(2,0,nTab), "lhs" + msOp + "rhs");
446 0 : pDoc->SetString(ScAddress(3,0,nTab), "expected");
447 0 : }
448 :
449 0 : virtual void addRow(ScDocument *pDoc, int nRow, int nTab) const SAL_OVERRIDE
450 : {
451 : double nLhs, nRhs;
452 :
453 0 : do {
454 0 : nLhs = comphelper::rng::uniform_real_distribution(mnRangeLo, mnRangeHi);
455 0 : nRhs = comphelper::rng::uniform_real_distribution(mnRangeLo, mnRangeHi);
456 0 : } while (mpFilterOut != nullptr && mpFilterOut(nLhs, nRhs));
457 :
458 0 : pDoc->SetValue(ScAddress(0,1+nRow,nTab), nLhs);
459 0 : pDoc->SetValue(ScAddress(1,1+nRow,nTab), nRhs);
460 :
461 : pDoc->SetString(ScAddress(2,1+nRow,nTab),
462 0 : "=" + ScAddress(0,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
463 0 : msOp + ScAddress(1,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW));
464 :
465 0 : pDoc->SetValue(ScAddress(3,1+nRow,nTab), mpFun(nLhs, nRhs));
466 :
467 : pDoc->SetString(ScAddress(4,1+nRow,nTab),
468 0 : "=IF(ABS(" + ScAddress(2,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
469 0 : "-" + ScAddress(3,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
470 0 : ")<=" + OUString::number(mnEpsilon) +
471 0 : ",0,1)");
472 0 : }
473 :
474 0 : virtual OUString getSummaryFormula(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
475 : {
476 0 : return "=SUM(" +
477 : ScRange(ScAddress(4,1,nTab),
478 0 : ScAddress(4,1+mnRows-1,nTab)).Format(SCA_VALID|SCA_TAB_3D|SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB, pDoc) +
479 0 : ")";
480 : }
481 : };
482 :
483 : struct Round : Area
484 : {
485 0 : Round() :
486 0 : Area("Round")
487 : {
488 0 : }
489 :
490 0 : virtual ~Round()
491 0 : {
492 0 : }
493 :
494 0 : virtual void addHeader(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
495 : {
496 0 : pDoc->SetString(ScAddress(0,0,nTab), "x");
497 0 : pDoc->SetString(ScAddress(1,0,nTab), "n");
498 0 : pDoc->SetString(ScAddress(2,0,nTab), "ROUND(x,n)");
499 0 : pDoc->SetString(ScAddress(3,0,nTab), "expected");
500 0 : }
501 :
502 0 : virtual void addRow(ScDocument *pDoc, int nRow, int nTab) const SAL_OVERRIDE
503 : {
504 0 : const double nX(comphelper::rng::uniform_real_distribution(0, 100));
505 0 : const int nN(comphelper::rng::uniform_int_distribution(1, 10));
506 :
507 0 : pDoc->SetValue(ScAddress(0,1+nRow,nTab), nX);
508 0 : pDoc->SetValue(ScAddress(1,1+nRow,nTab), nN);
509 :
510 : pDoc->SetString(ScAddress(2,1+nRow,nTab),
511 0 : "=ROUND(" + ScAddress(0,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
512 0 : "," + ScAddress(1,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
513 0 : ")");
514 :
515 0 : pDoc->SetValue(ScAddress(3,1+nRow,nTab), ::rtl::math::round(nX, (short) nN, rtl_math_RoundingMode_Corrected));
516 :
517 : pDoc->SetString(ScAddress(4,1+nRow,nTab),
518 0 : "=IF(ABS(" + ScAddress(2,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
519 0 : "-" + ScAddress(3,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
520 : ")<=3e-10"
521 0 : ",0,1)");
522 0 : }
523 :
524 0 : virtual OUString getSummaryFormula(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
525 : {
526 0 : return "=SUM(" +
527 : ScRange(ScAddress(4,1,nTab),
528 0 : ScAddress(4,1+mnRows-1,nTab)).Format(SCA_VALID|SCA_TAB_3D|SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB, pDoc) +
529 0 : ")";
530 : }
531 :
532 : };
533 :
534 : struct Normdist : Area
535 : {
536 0 : Normdist() :
537 0 : Area("Normdist")
538 : {
539 0 : }
540 :
541 0 : virtual ~Normdist()
542 0 : {
543 0 : }
544 :
545 0 : virtual void addHeader(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
546 : {
547 0 : pDoc->SetString(ScAddress(0,0,nTab), "num");
548 0 : pDoc->SetString(ScAddress(1,0,nTab), "avg");
549 0 : pDoc->SetString(ScAddress(2,0,nTab), "stdev");
550 0 : pDoc->SetString(ScAddress(3,0,nTab), "type");
551 0 : pDoc->SetString(ScAddress(4,0,nTab), "NORMDIST(num,avg,stdev,type)");
552 0 : pDoc->SetString(ScAddress(5,0,nTab), "expected");
553 0 : }
554 :
555 0 : virtual void addRow(ScDocument *pDoc, int nRow, int nTab) const SAL_OVERRIDE
556 : {
557 0 : const double nNum(comphelper::rng::uniform_real_distribution(0, 100));
558 0 : const double nAvg(comphelper::rng::uniform_real_distribution(0, 100));
559 0 : const double nStDev(comphelper::rng::uniform_real_distribution(1, 10));
560 0 : const int nType(comphelper::rng::uniform_int_distribution(0, 1));
561 :
562 0 : pDoc->SetValue(ScAddress(0,1+nRow,nTab), nNum);
563 0 : pDoc->SetValue(ScAddress(1,1+nRow,nTab), nAvg);
564 0 : pDoc->SetValue(ScAddress(2,1+nRow,nTab), nStDev);
565 0 : pDoc->SetValue(ScAddress(3,1+nRow,nTab), nType);
566 :
567 : pDoc->SetString(ScAddress(4,1+nRow,nTab),
568 0 : "=NORMDIST(" + ScAddress(0,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
569 0 : "," + ScAddress(1,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
570 0 : "," + ScAddress(2,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
571 0 : "," + ScAddress(3,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
572 0 : ")");
573 :
574 0 : if (nType == 1)
575 0 : pDoc->SetValue(ScAddress(5,1+nRow,nTab), ScInterpreter::integralPhi((nNum-nAvg)/nStDev));
576 : else
577 0 : pDoc->SetValue(ScAddress(5,1+nRow,nTab), ScInterpreter::phi((nNum-nAvg)/nStDev)/nStDev);
578 :
579 : pDoc->SetString(ScAddress(6,1+nRow,nTab),
580 0 : "=IF(ABS(" + ScAddress(4,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
581 0 : "-" + ScAddress(5,1+nRow,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
582 : ")<=3e-10"
583 0 : ",0,1)");
584 0 : }
585 :
586 0 : virtual OUString getSummaryFormula(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
587 : {
588 0 : return "=SUM(" +
589 : ScRange(ScAddress(6,1,nTab),
590 0 : ScAddress(6,1+mnRows-1,nTab)).Format(SCA_VALID|SCA_TAB_3D|SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB, pDoc) +
591 0 : ")";
592 : }
593 :
594 : };
595 :
596 : struct Reduction : Op
597 : {
598 : double mnAccumInitial;
599 : double (*mpFun)(double nAccum, double nArg, const Reduction& rReduction);
600 : bool (*mpFilterOut)(double nArg);
601 :
602 0 : Reduction(const OUString& rTitle,
603 : const OUString& rOp,
604 : double nAccumInitial,
605 : double nRangeLo, double nRangeHi,
606 : double nEpsilon,
607 : double (*pFun)(double nAccum, double nArg, const Reduction& rReduction),
608 : bool (*pFilterOut)(double nArg) = nullptr) :
609 : Op(rTitle, rOp, nRangeLo, nRangeHi, nEpsilon),
610 : mnAccumInitial(nAccumInitial),
611 : mpFun(pFun),
612 0 : mpFilterOut(pFilterOut)
613 : {
614 0 : }
615 :
616 0 : virtual ~Reduction()
617 0 : {
618 0 : }
619 :
620 0 : virtual void addHeader(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
621 : {
622 0 : pDoc->SetString(ScAddress(0,0,nTab), "x");
623 0 : pDoc->SetString(ScAddress(1,0,nTab), msOp);
624 0 : pDoc->SetString(ScAddress(2,0,nTab), "expected");
625 0 : }
626 :
627 0 : virtual void addRow(ScDocument *pDoc, int nRow, int nTab) const SAL_OVERRIDE
628 : {
629 : double nArg;
630 :
631 0 : do {
632 0 : nArg = comphelper::rng::uniform_real_distribution(mnRangeLo, mnRangeHi);
633 0 : } while (mpFilterOut != nullptr && mpFilterOut(nArg));
634 :
635 0 : pDoc->SetValue(ScAddress(0,1+nRow,nTab), nArg);
636 :
637 0 : if (nRow >= mnRows/2-1)
638 : {
639 0 : pDoc->SetString(ScAddress(1,1+nRow-mnRows/2+1,nTab),
640 0 : "=" + msOp + "(" +
641 0 : ScRange(ScAddress(0,1+nRow-mnRows/2+1,nTab),
642 0 : ScAddress(0,1+nRow,nTab)).Format(SCA_VALID|SCA_TAB_3D|SCA_VALID_COL|SCA_VALID_ROW) +
643 0 : ")");
644 :
645 0 : double nAccum(mnAccumInitial);
646 0 : for (int i = 0; i < mnRows/2; i++)
647 0 : nAccum = mpFun(nAccum, pDoc->GetValue(ScAddress(0,1+nRow-mnRows/2+i+1,nTab)), *this);
648 :
649 0 : pDoc->SetValue(ScAddress(2,1+nRow-mnRows/2+1,nTab), nAccum);
650 :
651 0 : if (mnEpsilon != 0)
652 0 : pDoc->SetString(ScAddress(3,1+nRow-mnRows/2+1,nTab),
653 0 : "=IF(ABS(" + ScAddress(1,1+nRow-mnRows/2+1,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
654 0 : "-" + ScAddress(2,1+nRow-mnRows/2+1,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
655 0 : ")<=" + OUString::number(mnEpsilon) +
656 0 : ",0,1)");
657 : else
658 0 : pDoc->SetString(ScAddress(3,1+nRow-mnRows/2+1,nTab),
659 0 : "=IF(" + ScAddress(1,1+nRow-mnRows/2+1,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
660 0 : "=" + ScAddress(2,1+nRow-mnRows/2+1,nTab).Format(SCA_VALID_COL|SCA_VALID_ROW) +
661 0 : ",0,1)");
662 : }
663 0 : }
664 :
665 0 : virtual OUString getSummaryFormula(ScDocument *pDoc, int nTab) const SAL_OVERRIDE
666 : {
667 0 : return "=SUM(" +
668 : ScRange(ScAddress(3,1+0,nTab),
669 0 : ScAddress(3,1+mnRows-mnRows/2-1,nTab)).Format(SCA_VALID|SCA_TAB_3D|SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB, pDoc) +
670 0 : ")";
671 : }
672 : };
673 :
674 : }
675 :
676 0 : IMPL_STATIC_LINK(
677 : ScCalcOptionsDialog, TestClickHdl, PushButton*, pButton)
678 : {
679 0 : pButton->Disable();
680 :
681 : // Automatically test the current implementation of OpenCL. If it
682 : // seems good, whitelist it. If it seems bad, blacklist it.
683 :
684 0 : std::unique_ptr<OpenCLTester> xTestDocument(new OpenCLTester());
685 :
686 : xTestDocument->addTest(BinOp("Plus", "+", -1000, 1000, 3e-10,
687 0 : [] (double nLhs, double nRhs)
688 : {
689 : return nLhs + nRhs;
690 0 : }));
691 :
692 : xTestDocument->addTest(BinOp("Minus", "-", -1000, 1000, 3e-10,
693 0 : [] (double nLhs, double nRhs)
694 : {
695 : return nLhs - nRhs;
696 0 : }));
697 :
698 : xTestDocument->addTest(BinOp("Times", "*", -1000, 1000, 3e-10,
699 0 : [] (double nLhs, double nRhs)
700 : {
701 : return nLhs * nRhs;
702 0 : }));
703 :
704 : xTestDocument->addTest(BinOp("Divided", "/", -1000, 1000, 3e-10,
705 0 : [] (double nLhs, double nRhs)
706 : {
707 : return nLhs / nRhs;
708 0 : },
709 0 : [] (double, double nRhs)
710 : {
711 : return (nRhs == 0);
712 0 : }));
713 :
714 : xTestDocument->addTest(UnOp("Sin", "SIN", -10, 10, 3e-10,
715 0 : [] (double nArg)
716 : {
717 : return sin(nArg);
718 0 : }));
719 :
720 : xTestDocument->addTest(UnOp("Cos", "COS", -10, 10, 3e-10,
721 0 : [] (double nArg)
722 : {
723 : return cos(nArg);
724 0 : }));
725 :
726 : xTestDocument->addTest(UnOp("Tan", "TAN", 0, 10, -3e-10,
727 0 : [] (double nArg)
728 : {
729 : return tan(nArg);
730 0 : },
731 0 : [] (double nArg)
732 : {
733 0 : return (std::fmod(nArg, M_PI) == M_PI/2);
734 0 : }));
735 :
736 : xTestDocument->addTest(UnOp("Atan", "ATAN", -10, 10, 3e-10,
737 0 : [] (double nArg)
738 : {
739 : return atan(nArg);
740 0 : }));
741 :
742 : xTestDocument->addTest(UnOp("Sqrt", "SQRT", 0, 1000, 3e-10,
743 0 : [] (double nArg)
744 : {
745 : return sqrt(nArg);
746 0 : }));
747 :
748 : xTestDocument->addTest(UnOp("Exp", "EXP", 0, 10, 3e-10,
749 0 : [] (double nArg)
750 : {
751 : return exp(nArg);
752 0 : }));
753 :
754 : xTestDocument->addTest(UnOp("Ln", "LN", 0, 1000, 3e-10,
755 0 : [] (double nArg)
756 : {
757 : return log(nArg);
758 0 : },
759 0 : [] (double nArg)
760 : {
761 : return (nArg == 0);
762 0 : }));
763 :
764 : xTestDocument->addTest(UnOp("NormSInv", "NORMSINV", 0, 1, 3e-10,
765 0 : [] (double nArg)
766 : {
767 : return ScInterpreter::gaussinv(nArg);
768 0 : }));
769 :
770 0 : xTestDocument->addTest(Round());
771 :
772 0 : xTestDocument->addTest(Normdist());
773 :
774 : xTestDocument->addTest(Reduction("Sum", "SUM", 0, -1000, 1000, 3e-10,
775 0 : [] (double nAccum, double nArg, const Reduction&)
776 : {
777 : return (nAccum + nArg);
778 0 : }));
779 :
780 : xTestDocument->addTest(Reduction("Average", "AVERAGE", 0, -1000, 1000, 3e-10,
781 0 : [] (double nAccum, double nArg, const Reduction& rReduction)
782 : {
783 0 : return (nAccum + nArg/(rReduction.mnRows/2));
784 0 : }));
785 :
786 : xTestDocument->addTest(Reduction("Product", "PRODUCT", 1, 0.1, 2.5, 3e-10,
787 0 : [] (double nAccum, double nArg, const Reduction&)
788 : {
789 : return (nAccum * nArg);
790 0 : }));
791 :
792 : xTestDocument->addTest(Reduction("Min", "MIN", DBL_MAX, -1000, 1000, 0,
793 0 : [] (double nAccum, double nArg, const Reduction&)
794 : {
795 0 : return std::min(nAccum, nArg);
796 0 : }));
797 :
798 : xTestDocument->addTest(Reduction("Max", "MAX", -DBL_MAX, -1000, 1000, 0,
799 0 : [] (double nAccum, double nArg, const Reduction&)
800 : {
801 0 : return std::max(nAccum, nArg);
802 0 : }));
803 :
804 0 : xTestDocument->mpDoc->CalcAll();
805 0 : ScInterpreter::SetGlobalConfig(xTestDocument->maOldCalcConfig);
806 :
807 0 : return 0;
808 0 : }
809 :
810 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|