Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <sfx2/linkmgr.hxx>
30 : : #include <sfx2/dispatch.hxx>
31 : : #include <sfx2/objsh.hxx>
32 : : #include <svl/stritem.hxx>
33 : : #include <svl/zforlist.hxx>
34 : : #include <rtl/logfile.hxx>
35 : : #include <sal/macros.h>
36 : :
37 : : #include "interpre.hxx"
38 : : #include "attrib.hxx"
39 : : #include "sc.hrc"
40 : : #include "ddelink.hxx"
41 : : #include "scmatrix.hxx"
42 : : #include "compiler.hxx"
43 : : #include "cell.hxx"
44 : : #include "document.hxx"
45 : : #include "dociter.hxx"
46 : : #include "docoptio.hxx"
47 : : #include "unitconv.hxx"
48 : : #include "globstr.hrc"
49 : : #include "hints.hxx"
50 : : #include "dpobject.hxx"
51 : : #include "postit.hxx"
52 : :
53 : : #include <string.h>
54 : : #include <math.h>
55 : :
56 : : using namespace formula;
57 : : // STATIC DATA -----------------------------------------------------------
58 : :
59 : : #define D_TIMEFACTOR 86400.0
60 : : #define SCdEpsilon 1.0E-7
61 : :
62 : : //-----------------------------------------------------------------------------
63 : : // Datum und Zeit
64 : : //-----------------------------------------------------------------------------
65 : :
66 : 0 : double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
67 : : bool bStrict, bool bCheckGregorian )
68 : : {
69 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDateSerial" );
70 [ # # ][ # # ]: 0 : if ( nYear < 100 && !bStrict )
71 [ # # ]: 0 : nYear = pFormatter->ExpandTwoDigitYear( nYear );
72 : : // Do not use a default Date ctor here because it asks system time with a
73 : : // performance penalty.
74 : : sal_Int16 nY, nM, nD;
75 [ # # ]: 0 : if (bStrict)
76 : 0 : nY = nYear, nM = nMonth, nD = nDay;
77 : : else
78 : : {
79 [ # # ]: 0 : if (nMonth > 0)
80 : : {
81 : 0 : nY = nYear + (nMonth-1) / 12;
82 : 0 : nM = ((nMonth-1) % 12) + 1;
83 : : }
84 : : else
85 : : {
86 : 0 : nY = nYear + (nMonth-12) / 12;
87 : 0 : nM = 12 - (-nMonth) % 12;
88 : : }
89 : 0 : nD = 1;
90 : : }
91 : 0 : Date aDate( nD, nM, nY);
92 [ # # ]: 0 : if (!bStrict)
93 [ # # ]: 0 : aDate += nDay - 1;
94 [ # # ][ # # ]: 0 : if ((!bCheckGregorian && aDate.IsValidDate()) || (bCheckGregorian && aDate.IsValidAndGregorian()))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
95 [ # # ][ # # ]: 0 : return (double) (aDate - *(pFormatter->GetNullDate()));
96 : : else
97 : : {
98 : 0 : SetError(errNoValue);
99 : 0 : return 0;
100 : : }
101 : : }
102 : :
103 : : //-----------------------------------------------------------------------------
104 : : // Funktionen
105 : : //-----------------------------------------------------------------------------
106 : :
107 : 0 : void ScInterpreter::ScGetActDate()
108 : : {
109 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActDate" );
110 : 0 : nFuncFmtType = NUMBERFORMAT_DATE;
111 [ # # ]: 0 : Date aActDate( Date::SYSTEM );
112 [ # # ][ # # ]: 0 : long nDiff = aActDate - *(pFormatter->GetNullDate());
113 [ # # ]: 0 : PushDouble((double) nDiff);
114 : 0 : }
115 : :
116 : 9 : void ScInterpreter::ScGetActTime()
117 : : {
118 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActTime" );
119 : 9 : nFuncFmtType = NUMBERFORMAT_DATETIME;
120 [ + - ]: 9 : Date aActDate( Date::SYSTEM );
121 [ + - ][ + - ]: 9 : long nDiff = aActDate - *(pFormatter->GetNullDate());
122 [ + - ]: 9 : Time aActTime( Time::SYSTEM );
123 : 9 : double nTime = ((double)aActTime.Get100Sec() / 100 +
124 : 9 : (double)(aActTime.GetSec() +
125 : 9 : (aActTime.GetMin() * 60) +
126 : 9 : (aActTime.GetHour() * 3600))) / D_TIMEFACTOR;
127 [ + - ]: 9 : PushDouble( (double) nDiff + nTime );
128 : 9 : }
129 : :
130 : 0 : void ScInterpreter::ScGetYear()
131 : : {
132 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetYear" );
133 [ # # ]: 0 : Date aDate = *(pFormatter->GetNullDate());
134 [ # # ][ # # ]: 0 : aDate += (long) ::rtl::math::approxFloor(GetDouble());
135 [ # # ]: 0 : PushDouble( (double) aDate.GetYear() );
136 : 0 : }
137 : :
138 : 0 : void ScInterpreter::ScGetMonth()
139 : : {
140 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMonth" );
141 [ # # ]: 0 : Date aDate = *(pFormatter->GetNullDate());
142 [ # # ][ # # ]: 0 : aDate += (long) ::rtl::math::approxFloor(GetDouble());
143 [ # # ]: 0 : PushDouble( (double) aDate.GetMonth() );
144 : 0 : }
145 : :
146 : 0 : void ScInterpreter::ScGetDay()
147 : : {
148 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDay" );
149 [ # # ]: 0 : Date aDate = *(pFormatter->GetNullDate());
150 [ # # ][ # # ]: 0 : aDate += (long)::rtl::math::approxFloor(GetDouble());
151 [ # # ]: 0 : PushDouble((double) aDate.GetDay());
152 : 0 : }
153 : :
154 : 0 : void ScInterpreter::ScGetMin()
155 : : {
156 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMin" );
157 : 0 : double fTime = GetDouble();
158 : 0 : fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
159 : 0 : long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 3600;
160 : 0 : PushDouble( (double) (nVal/60) );
161 : 0 : }
162 : :
163 : 0 : void ScInterpreter::ScGetSec()
164 : : {
165 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetSec" );
166 : 0 : double fTime = GetDouble();
167 : 0 : fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
168 : 0 : long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 60;
169 : 0 : PushDouble( (double) nVal );
170 : 0 : }
171 : :
172 : 0 : void ScInterpreter::ScGetHour()
173 : : {
174 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetHour" );
175 : 0 : double fTime = GetDouble();
176 : 0 : fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
177 : 0 : long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) / 3600;
178 : 0 : PushDouble((double) nVal);
179 : 0 : }
180 : :
181 : 0 : void ScInterpreter::ScGetDateValue()
182 : : {
183 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDateValue" );
184 [ # # ][ # # ]: 0 : String aInputString = GetString();
185 : 0 : sal_uInt32 nFIndex = 0; // damit default Land/Spr.
186 : : double fVal;
187 [ # # ][ # # ]: 0 : if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
188 : : {
189 [ # # ]: 0 : short eType = pFormatter->GetType(nFIndex);
190 [ # # ][ # # ]: 0 : if (eType == NUMBERFORMAT_DATE || eType == NUMBERFORMAT_DATETIME)
191 [ # # ]: 0 : PushDouble(::rtl::math::approxFloor(fVal));
192 : : else
193 [ # # ]: 0 : PushIllegalArgument();
194 : : }
195 : : else
196 [ # # ][ # # ]: 0 : PushIllegalArgument();
197 : 0 : }
198 : :
199 : 0 : void ScInterpreter::ScGetDayOfWeek()
200 : : {
201 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDayOfWeek" );
202 : 0 : sal_uInt8 nParamCount = GetByte();
203 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
204 : : {
205 : : short nFlag;
206 [ # # ]: 0 : if (nParamCount == 2)
207 [ # # ]: 0 : nFlag = (short) ::rtl::math::approxFloor(GetDouble());
208 : : else
209 : 0 : nFlag = 1;
210 : :
211 [ # # ]: 0 : Date aDate = *(pFormatter->GetNullDate());
212 [ # # ][ # # ]: 0 : aDate += (long)::rtl::math::approxFloor(GetDouble());
213 [ # # ]: 0 : int nVal = (int) aDate.GetDayOfWeek();
214 [ # # ]: 0 : if (nFlag == 1)
215 : : {
216 [ # # ]: 0 : if (nVal == 6)
217 : 0 : nVal = 1;
218 : : else
219 : 0 : nVal += 2;
220 : : }
221 [ # # ]: 0 : else if (nFlag == 2)
222 : 0 : nVal += 1;
223 [ # # ]: 0 : PushInt( nVal );
224 : : }
225 : 0 : }
226 : :
227 : 0 : void ScInterpreter::ScGetWeekOfYear()
228 : : {
229 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetWeekOfYear" );
230 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
231 : : {
232 [ # # ]: 0 : short nFlag = (short) ::rtl::math::approxFloor(GetDouble());
233 : :
234 [ # # ]: 0 : Date aDate = *(pFormatter->GetNullDate());
235 [ # # ][ # # ]: 0 : aDate += (long)::rtl::math::approxFloor(GetDouble());
236 [ # # ][ # # ]: 0 : PushInt( (int) aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY ));
[ # # ]
237 : : }
238 : 0 : }
239 : :
240 : 0 : void ScInterpreter::ScEasterSunday()
241 : : {
242 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEasterSunday" );
243 : 0 : nFuncFmtType = NUMBERFORMAT_DATE;
244 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 1 ) )
245 : : {
246 : : sal_Int16 nDay, nMonth, nYear;
247 : 0 : nYear = (sal_Int16) ::rtl::math::approxFloor( GetDouble() );
248 [ # # ]: 0 : if ( nYear < 100 )
249 : 0 : nYear = pFormatter->ExpandTwoDigitYear( nYear );
250 : : // don't worry, be happy :)
251 : : int B,C,D,E,F,G,H,I,K,L,M,N,O;
252 : 0 : N = nYear % 19;
253 : 0 : B = int(nYear / 100);
254 : 0 : C = nYear % 100;
255 : 0 : D = int(B / 4);
256 : 0 : E = B % 4;
257 : 0 : F = int((B + 8) / 25);
258 : 0 : G = int((B - F + 1) / 3);
259 : 0 : H = (19 * N + B - D - G + 15) % 30;
260 : 0 : I = int(C / 4);
261 : 0 : K = C % 4;
262 : 0 : L = (32 + 2 * E + 2 * I - H - K) % 7;
263 : 0 : M = int((N + 11 * H + 22 * L) / 451);
264 : 0 : O = H + L - 7 * M + 114;
265 : 0 : nDay = sal::static_int_cast<sal_Int16>( O % 31 + 1 );
266 : 0 : nMonth = sal::static_int_cast<sal_Int16>( int(O / 31) );
267 : 0 : PushDouble( GetDateSerial( nYear, nMonth, nDay, true, true ) );
268 : : }
269 : 0 : }
270 : :
271 : 0 : void ScInterpreter::ScGetDate()
272 : : {
273 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDate" );
274 : 0 : nFuncFmtType = NUMBERFORMAT_DATE;
275 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
276 : : {
277 : 0 : sal_Int16 nDay = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
278 : 0 : sal_Int16 nMonth = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
279 : 0 : sal_Int16 nYear = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
280 [ # # ]: 0 : if (nYear < 0)
281 : 0 : PushIllegalArgument();
282 : : else
283 : : {
284 : 0 : PushDouble(GetDateSerial(nYear, nMonth, nDay, false, true));
285 : : }
286 : : }
287 : 0 : }
288 : :
289 : 0 : void ScInterpreter::ScGetTime()
290 : : {
291 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTime" );
292 : 0 : nFuncFmtType = NUMBERFORMAT_TIME;
293 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
294 : : {
295 : 0 : double nSec = GetDouble();
296 : 0 : double nMin = GetDouble();
297 : 0 : double nHour = GetDouble();
298 : 0 : double fTime = fmod( (nHour * 3600) + (nMin * 60) + nSec, D_TIMEFACTOR) / D_TIMEFACTOR;
299 [ # # ]: 0 : if (fTime < 0)
300 : 0 : PushIllegalArgument();
301 : : else
302 : 0 : PushDouble( fTime);
303 : : }
304 : 0 : }
305 : :
306 : 0 : void ScInterpreter::ScGetDiffDate()
307 : : {
308 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate" );
309 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
310 : : {
311 : 0 : double nDate2 = GetDouble();
312 : 0 : double nDate1 = GetDouble();
313 : 0 : PushDouble(nDate1 - nDate2);
314 : : }
315 : 0 : }
316 : :
317 : 0 : void ScInterpreter::ScGetDiffDate360()
318 : : {
319 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate360" );
320 : : /* Implementation follows
321 : : * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
322 : : * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
323 : : * 30-days count. That document also claims that Excel implements the "PSA
324 : : * 30" or "NASD 30" method (funny enough they also state that Excel is the
325 : : * only tool that does so).
326 : : *
327 : : * Note that the definiton given in
328 : : * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
329 : : * is _not_ the way how it is actually calculated by Excel (that would not
330 : : * even match any of the 7 methods mentioned above) and would result in the
331 : : * following test cases producing wrong results according to that appendix B:
332 : : *
333 : : * 28-Feb-95 31-Aug-95 181 instead of 180
334 : : * 29-Feb-96 31-Aug-96 181 instead of 180
335 : : * 30-Jan-96 31-Mar-96 61 instead of 60
336 : : * 31-Jan-96 31-Mar-96 61 instead of 60
337 : : *
338 : : * Still, there is a difference between OOoCalc and Excel:
339 : : * In Excel:
340 : : * 02-Feb-99 31-Mar-00 results in 419
341 : : * 31-Mar-00 02-Feb-99 results in -418
342 : : * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
343 : : */
344 : :
345 : 0 : sal_uInt8 nParamCount = GetByte();
346 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
347 : : {
348 : : bool bFlag;
349 [ # # ]: 0 : if (nParamCount == 3)
350 : 0 : bFlag = GetBool();
351 : : else
352 : 0 : bFlag = false;
353 : 0 : double nDate2 = GetDouble();
354 : 0 : double nDate1 = GetDouble();
355 [ # # ]: 0 : if (nGlobalError)
356 : 0 : PushError( nGlobalError);
357 : : else
358 : : {
359 : : double fSign;
360 : : // #i84934# only for non-US European algorithm swap dates. Else
361 : : // follow Excel's meaningless extrapolation for "interoperability".
362 [ # # ][ # # ]: 0 : if (bFlag && (nDate2 < nDate1))
363 : : {
364 : 0 : fSign = nDate1;
365 : 0 : nDate1 = nDate2;
366 : 0 : nDate2 = fSign;
367 : 0 : fSign = -1.0;
368 : : }
369 : : else
370 : 0 : fSign = 1.0;
371 [ # # ]: 0 : Date aDate1 = *(pFormatter->GetNullDate());
372 [ # # ]: 0 : aDate1 += (long) ::rtl::math::approxFloor(nDate1);
373 [ # # ]: 0 : Date aDate2 = *(pFormatter->GetNullDate());
374 [ # # ]: 0 : aDate2 += (long) ::rtl::math::approxFloor(nDate2);
375 [ # # ]: 0 : if (aDate1.GetDay() == 31)
376 [ # # ]: 0 : aDate1 -= (sal_uLong) 1;
377 [ # # ]: 0 : else if (!bFlag)
378 : : {
379 [ # # ]: 0 : if (aDate1.GetMonth() == 2)
380 : : {
381 [ # # # ]: 0 : switch ( aDate1.GetDay() )
382 : : {
383 : : case 28 :
384 [ # # ][ # # ]: 0 : if ( !aDate1.IsLeapYear() )
385 [ # # ]: 0 : aDate1.SetDay(30);
386 : 0 : break;
387 : : case 29 :
388 [ # # ]: 0 : aDate1.SetDay(30);
389 : 0 : break;
390 : : }
391 : : }
392 : : }
393 [ # # ]: 0 : if (aDate2.GetDay() == 31)
394 : : {
395 [ # # ]: 0 : if (!bFlag )
396 : : {
397 [ # # ]: 0 : if (aDate1.GetDay() == 30)
398 [ # # ]: 0 : aDate2 -= (sal_uLong) 1;
399 : : }
400 : : else
401 [ # # ]: 0 : aDate2.SetDay(30);
402 : : }
403 : : PushDouble( fSign * (double)
404 : 0 : ( (double) aDate2.GetDay() + (double) aDate2.GetMonth() * 30.0 +
405 : 0 : (double) aDate2.GetYear() * 360.0
406 : 0 : - (double) aDate1.GetDay() - (double) aDate1.GetMonth() * 30.0
407 [ # # ]: 0 : - (double)aDate1.GetYear() * 360.0) );
408 : : }
409 : : }
410 : 0 : }
411 : :
412 : : // fdo#44456 function DATEDIF as defined in ODF1.2 (Par. 6.10.3)
413 : 270 : void ScInterpreter::ScGetDateDif()
414 : : {
415 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDateDif" );
416 [ + - ]: 270 : if ( MustHaveParamCount( GetByte(), 3 ) )
417 : : {
418 [ + - ][ + - ]: 270 : String aInterval = GetString();
419 [ + - ]: 270 : double nDate2 = GetDouble();
420 [ + - ]: 270 : double nDate1 = GetDouble();
421 : :
422 [ + + ]: 270 : if (nGlobalError)
423 : : {
424 [ + - ]: 60 : PushError( nGlobalError);
425 : : return;
426 : : }
427 : :
428 : : // Excel doesn't swap dates or return negative numbers, so don't we.
429 [ + + ]: 210 : if (nDate1 > nDate2)
430 : : {
431 [ + - ]: 18 : PushIllegalArgument();
432 : : return;
433 : : }
434 : :
435 : 192 : long dd = nDate2 - nDate1;
436 : : // Zero difference or number of days can be returned immediately.
437 [ + - ][ + - ]: 192 : if (dd == 0 || aInterval.EqualsIgnoreCaseAscii( "d" ))
[ + + ][ + + ]
438 : : {
439 [ + - ]: 42 : PushDouble( dd );
440 : : return;
441 : : }
442 : :
443 : : // split dates in day, month, year for use with formats other than "d"
444 : : sal_uInt16 d1, m1, y1, d2, m2, y2;
445 [ + - ]: 150 : Date aDate1( *( pFormatter->GetNullDate()));
446 [ + - ]: 150 : aDate1 += (long) ::rtl::math::approxFloor( nDate1 );
447 : 150 : y1 = aDate1.GetYear();
448 : 150 : m1 = aDate1.GetMonth();
449 : 150 : d1 = aDate1.GetDay();
450 [ + - ]: 150 : Date aDate2( *( pFormatter->GetNullDate()));
451 [ + - ]: 150 : aDate2 += (long) ::rtl::math::approxFloor( nDate2 );
452 : 150 : y2 = aDate2.GetYear();
453 : 150 : m2 = aDate2.GetMonth();
454 : 150 : d2 = aDate2.GetDay();
455 : :
456 [ + + ][ + - ]: 150 : if ( aInterval.EqualsIgnoreCaseAscii( "m" ) )
457 : : {
458 : : // Return number of months.
459 : 36 : int md = m2 - m1 + 12 * (y2 - y1);
460 [ + + ]: 36 : if (d1 > d2)
461 : 12 : --md;
462 [ + - ]: 36 : PushInt( md );
463 : : }
464 [ + - ][ + + ]: 114 : else if ( aInterval.EqualsIgnoreCaseAscii( "y" ) )
465 : : {
466 : : // Return number of years.
467 : : int yd;
468 [ + + ]: 18 : if ( y2 > y1 )
469 : : {
470 [ + - ][ - + ]: 12 : if (m2 > m1 || (m2 == m1 && d2 >= d1))
[ # # ]
471 : 0 : yd = y2 - y1; // complete years between dates
472 : : else
473 : 12 : yd = y2 - y1 - 1; // one incomplete year
474 : : }
475 : : else
476 : : {
477 : : // Year is equal as we don't allow reversed arguments, no
478 : : // complete year between dates.
479 : 6 : yd = 0;
480 : : }
481 [ + - ]: 18 : PushInt( yd );
482 : : }
483 [ + - ][ + + ]: 96 : else if ( aInterval.EqualsIgnoreCaseAscii( "md" ) )
484 : : {
485 : : // Return number of days, excluding months and years.
486 : : // This is actually the remainder of days when subtracting years
487 : : // and months from the difference of dates. Birthday-like 23 years
488 : : // and 10 months and 19 days.
489 : :
490 : : // Algorithm's roll-over behavior extracted from Excel by try and
491 : : // error..
492 : : // If day1 <= day2 then simply day2 - day1.
493 : : // If day1 > day2 then set month1 to month2-1 and year1 to
494 : : // year2(-1) and subtract dates, e.g. for 2012-01-28,2012-03-01 set
495 : : // 2012-02-28 and then (2012-03-01)-(2012-02-28) => 2 days (leap
496 : : // year).
497 : : // For 2011-01-29,2011-03-01 the non-existent 2011-02-29 rolls over
498 : : // to 2011-03-01 so the result is 0. Same for day 31 in months with
499 : : // only 30 days.
500 : :
501 : : long nd;
502 [ + - ]: 54 : if (d1 <= d2)
503 : 54 : nd = d2 - d1;
504 : : else
505 : : {
506 [ # # ]: 0 : if (m2 == 1)
507 : : {
508 [ # # ]: 0 : aDate1.SetYear( y2 - 1 );
509 [ # # ]: 0 : aDate1.SetMonth( 12 );
510 : : }
511 : : else
512 : : {
513 [ # # ]: 0 : aDate1.SetYear( y2 );
514 [ # # ]: 0 : aDate1.SetMonth( m2 - 1 );
515 : : }
516 [ # # ]: 0 : aDate1.Normalize();
517 [ # # ]: 0 : nd = aDate2 - aDate1;
518 : : }
519 [ + - ]: 54 : PushDouble( nd );
520 : : }
521 [ + - ][ + + ]: 42 : else if ( aInterval.EqualsIgnoreCaseAscii( "ym" ) )
522 : : {
523 : : // Return number of months, excluding years.
524 : 18 : int md = m2 - m1 + 12 * (y2 - y1);
525 [ + + ]: 18 : if (d1 > d2)
526 : 12 : --md;
527 : 18 : md %= 12;
528 [ + - ]: 18 : PushInt( md );
529 : : }
530 [ + - ][ + - ]: 24 : else if ( aInterval.EqualsIgnoreCaseAscii( "yd" ) )
531 : : {
532 : : // Return number of days, excluding years.
533 : :
534 : : /* TODO: check what Excel really does, though this seems to be
535 : : * reasonable */
536 : :
537 : : // Condition corresponds with "y".
538 [ + + ][ - + ]: 24 : if (m2 > m1 || (m2 == m1 && d2 >= d1))
[ # # ]
539 [ + - ]: 12 : aDate1.SetYear( y2 );
540 : : else
541 [ + - ]: 12 : aDate1.SetYear( y2 - 1 );
542 : : // XXX NOTE: Excel for the case 1988-06-22,2012-05-11 returns
543 : : // 323, whereas the result here is 324. Don't they use the leap
544 : : // year of 2012?
545 : : // http://www.cpearson.com/excel/datedif.aspx "DATEDIF And Leap
546 : : // Years" is not correct and Excel 2010 correctly returns 0 in
547 : : // both cases mentioned there. Also using year1 as mentioned
548 : : // produces incorrect results in other cases and different from
549 : : // Excel 2010. Apparently they fixed some calculations.
550 [ + - ]: 24 : aDate1.Normalize();
551 [ + - ]: 24 : double nd = aDate2 - aDate1;
552 [ + - ]: 24 : PushDouble( nd );
553 : : }
554 : : else
555 [ # # ][ + - ]: 270 : PushIllegalArgument(); // unsupported format
[ + + ]
556 : : }
557 : : }
558 : :
559 : 0 : void ScInterpreter::ScGetTimeValue()
560 : : {
561 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTimeValue" );
562 [ # # ][ # # ]: 0 : String aInputString = GetString();
563 : 0 : sal_uInt32 nFIndex = 0; // damit default Land/Spr.
564 : : double fVal;
565 [ # # ][ # # ]: 0 : if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
566 : : {
567 [ # # ]: 0 : short eType = pFormatter->GetType(nFIndex);
568 [ # # ][ # # ]: 0 : if (eType == NUMBERFORMAT_TIME || eType == NUMBERFORMAT_DATETIME)
569 : : {
570 : 0 : double fDateVal = rtl::math::approxFloor(fVal);
571 : 0 : double fTimeVal = fVal - fDateVal;
572 [ # # ]: 0 : PushDouble(fTimeVal);
573 : : }
574 : : else
575 [ # # ]: 0 : PushIllegalArgument();
576 : : }
577 : : else
578 [ # # ][ # # ]: 0 : PushIllegalArgument();
579 : 0 : }
580 : :
581 : 0 : void ScInterpreter::ScPlusMinus()
582 : : {
583 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPlusMinus" );
584 : 0 : double nVal = GetDouble();
585 : 0 : short n = 0;
586 [ # # ]: 0 : if (nVal < 0.0)
587 : 0 : n = -1;
588 [ # # ]: 0 : else if (nVal > 0.0)
589 : 0 : n = 1;
590 : 0 : PushInt( n );
591 : 0 : }
592 : :
593 : 9 : void ScInterpreter::ScAbs()
594 : : {
595 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAbs" );
596 : 9 : PushDouble(fabs(GetDouble()));
597 : 9 : }
598 : :
599 : 0 : void ScInterpreter::ScInt()
600 : : {
601 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInt" );
602 : 0 : PushDouble(::rtl::math::approxFloor(GetDouble()));
603 : 0 : }
604 : :
605 : :
606 : 12 : void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode )
607 : : {
608 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RoundNumber" );
609 : 12 : sal_uInt8 nParamCount = GetByte();
610 [ + - ]: 12 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
611 : : {
612 : 12 : double fVal = 0.0;
613 [ - + ]: 12 : if (nParamCount == 1)
614 : 0 : fVal = ::rtl::math::round( GetDouble(), 0, eMode );
615 : : else
616 : : {
617 : 12 : sal_Int32 nDec = (sal_Int32) ::rtl::math::approxFloor(GetDouble());
618 [ - + ][ + - ]: 12 : if( nDec < -20 || nDec > 20 )
619 : 0 : PushIllegalArgument();
620 : : else
621 : 12 : fVal = ::rtl::math::round( GetDouble(), (short)nDec, eMode );
622 : : }
623 : 12 : PushDouble(fVal);
624 : : }
625 : 12 : }
626 : :
627 : 12 : void ScInterpreter::ScRound()
628 : : {
629 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRound" );
630 : 12 : RoundNumber( rtl_math_RoundingMode_Corrected );
631 : 12 : }
632 : :
633 : 0 : void ScInterpreter::ScRoundDown()
634 : : {
635 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundDown" );
636 : 0 : RoundNumber( rtl_math_RoundingMode_Down );
637 : 0 : }
638 : :
639 : 0 : void ScInterpreter::ScRoundUp()
640 : : {
641 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundUp" );
642 : 0 : RoundNumber( rtl_math_RoundingMode_Up );
643 : 0 : }
644 : :
645 : 0 : void ScInterpreter::ScCeil()
646 : : {
647 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCeil" );
648 : 0 : sal_uInt8 nParamCount = GetByte();
649 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
650 : : {
651 [ # # ]: 0 : bool bAbs = ( nParamCount == 3 ? GetBool() : false );
652 : 0 : double fDec = GetDouble();
653 : 0 : double fVal = GetDouble();
654 [ # # ]: 0 : if ( fDec == 0.0 )
655 : 0 : PushInt(0);
656 [ # # ]: 0 : else if (fVal*fDec < 0.0)
657 : 0 : PushIllegalArgument();
658 : : else
659 : : {
660 [ # # ][ # # ]: 0 : if ( !bAbs && fVal < 0.0 )
661 : 0 : PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
662 : : else
663 : 0 : PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
664 : : }
665 : : }
666 : 0 : }
667 : :
668 : 0 : void ScInterpreter::ScFloor()
669 : : {
670 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFloor" );
671 : 0 : sal_uInt8 nParamCount = GetByte();
672 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
673 : : {
674 [ # # ]: 0 : bool bAbs = ( nParamCount == 3 ? GetBool() : false );
675 : 0 : double fDec = GetDouble();
676 : 0 : double fVal = GetDouble();
677 [ # # ]: 0 : if ( fDec == 0.0 )
678 : 0 : PushInt(0);
679 [ # # ]: 0 : else if (fVal*fDec < 0.0)
680 : 0 : PushIllegalArgument();
681 : : else
682 : : {
683 [ # # ][ # # ]: 0 : if ( !bAbs && fVal < 0.0 )
684 : 0 : PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
685 : : else
686 : 0 : PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
687 : : }
688 : : }
689 : 0 : }
690 : :
691 : 18 : void ScInterpreter::ScEven()
692 : : {
693 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEven" );
694 : 18 : double fVal = GetDouble();
695 [ + + ]: 18 : if (fVal < 0.0)
696 : 6 : PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0);
697 : : else
698 : 12 : PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0);
699 : 18 : }
700 : :
701 : 18 : void ScInterpreter::ScOdd()
702 : : {
703 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOdd" );
704 : 18 : double fVal = GetDouble();
705 [ + + ]: 18 : if (fVal >= 0.0)
706 : : {
707 : 12 : fVal = ::rtl::math::approxCeil(fVal);
708 [ + + ]: 12 : if (fmod(fVal, 2.0) == 0.0)
709 : 9 : fVal += 1.0;
710 : : }
711 : : else
712 : : {
713 : 6 : fVal = ::rtl::math::approxFloor(fVal);
714 [ + + ]: 6 : if (fmod(fVal, 2.0) == 0.0)
715 : 3 : fVal -= 1.0;
716 : : }
717 : 18 : PushDouble(fVal);
718 : 18 : }
719 : :
720 : 0 : void ScInterpreter::ScArcTan2()
721 : : {
722 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan2" );
723 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
724 : : {
725 : 0 : double nVal2 = GetDouble();
726 : 0 : double nVal1 = GetDouble();
727 : 0 : PushDouble(atan2(nVal2, nVal1));
728 : : }
729 : 0 : }
730 : :
731 : 0 : void ScInterpreter::ScLog()
732 : : {
733 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog" );
734 : 0 : sal_uInt8 nParamCount = GetByte();
735 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
736 : : {
737 : : double nBase;
738 [ # # ]: 0 : if (nParamCount == 2)
739 : 0 : nBase = GetDouble();
740 : : else
741 : 0 : nBase = 10.0;
742 : 0 : double nVal = GetDouble();
743 [ # # ][ # # ]: 0 : if (nVal > 0.0 && nBase > 0.0 && nBase != 1.0)
[ # # ]
744 : 0 : PushDouble(log(nVal) / log(nBase));
745 : : else
746 : 0 : PushIllegalArgument();
747 : : }
748 : 0 : }
749 : :
750 : 0 : void ScInterpreter::ScLn()
751 : : {
752 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLn" );
753 : 0 : double fVal = GetDouble();
754 [ # # ]: 0 : if (fVal > 0.0)
755 : 0 : PushDouble(log(fVal));
756 : : else
757 : 0 : PushIllegalArgument();
758 : 0 : }
759 : :
760 : 0 : void ScInterpreter::ScLog10()
761 : : {
762 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog10" );
763 : 0 : double fVal = GetDouble();
764 [ # # ]: 0 : if (fVal > 0.0)
765 : 0 : PushDouble(log10(fVal));
766 : : else
767 : 0 : PushIllegalArgument();
768 : 0 : }
769 : :
770 : 0 : void ScInterpreter::ScNPV()
771 : : {
772 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNPV" );
773 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
774 : 0 : short nParamCount = GetByte();
775 [ # # ][ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 2, 31 ) )
776 : : {
777 : 0 : double nVal = 0.0;
778 : : // Wir drehen den Stack um!!
779 : : FormulaToken* pTemp[ 31 ];
780 [ # # ]: 0 : for( short i = 0; i < nParamCount; i++ )
781 : 0 : pTemp[ i ] = pStack[ sp - i - 1 ];
782 : 0 : memcpy( &pStack[ sp - nParamCount ], pTemp, nParamCount * sizeof( FormulaToken* ) );
783 [ # # ]: 0 : if (nGlobalError == 0)
784 : : {
785 : 0 : double nCount = 1.0;
786 [ # # ]: 0 : double nZins = GetDouble();
787 : 0 : --nParamCount;
788 : 0 : size_t nRefInList = 0;
789 : 0 : ScRange aRange;
790 [ # # ]: 0 : while (nParamCount-- > 0)
791 : : {
792 [ # # ]: 0 : switch (GetStackType())
[ # # # # ]
793 : : {
794 : : case svDouble :
795 : : {
796 [ # # ]: 0 : nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount));
797 : 0 : nCount++;
798 : : }
799 : 0 : break;
800 : : case svSingleRef :
801 : : {
802 : 0 : ScAddress aAdr;
803 [ # # ]: 0 : PopSingleRef( aAdr );
804 [ # # ]: 0 : ScBaseCell* pCell = GetCell( aAdr );
805 [ # # ][ # # ]: 0 : if (!HasCellEmptyData(pCell) && HasCellValueData(pCell))
[ # # ][ # # ]
[ # # ]
806 : : {
807 [ # # ]: 0 : double nCellVal = GetCellValue( aAdr, pCell );
808 : 0 : nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
809 : 0 : nCount++;
810 : : }
811 : : }
812 : 0 : break;
813 : : case svDoubleRef :
814 : : case svRefList :
815 : : {
816 : 0 : sal_uInt16 nErr = 0;
817 : : double nCellVal;
818 [ # # ]: 0 : PopDoubleRef( aRange, nParamCount, nRefInList);
819 [ # # ]: 0 : ScHorizontalValueIterator aValIter( pDok, aRange, glSubTotal);
820 [ # # ][ # # ]: 0 : while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
[ # # ][ # # ]
821 : : {
822 : 0 : nVal += (nCellVal / pow(1.0 + nZins, (double)nCount));
823 : 0 : nCount++;
824 : : }
825 [ # # ]: 0 : if ( nErr != 0 )
826 [ # # ]: 0 : SetError(nErr);
827 : : }
828 : 0 : break;
829 : 0 : default : SetError(errIllegalParameter); break;
830 : : }
831 : : }
832 : : }
833 [ # # ]: 0 : PushDouble(nVal);
834 : : }
835 : 0 : }
836 : :
837 : 0 : void ScInterpreter::ScIRR()
838 : : {
839 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIRR" );
840 : : double fSchaetzwert;
841 : 0 : nFuncFmtType = NUMBERFORMAT_PERCENT;
842 : 0 : sal_uInt8 nParamCount = GetByte();
843 [ # # ][ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
844 : : return;
845 [ # # ]: 0 : if (nParamCount == 2)
846 [ # # ]: 0 : fSchaetzwert = GetDouble();
847 : : else
848 : 0 : fSchaetzwert = 0.1;
849 : 0 : sal_uInt16 sPos = sp; // Stack-Position merken
850 : 0 : double fEps = 1.0;
851 : : double x, xNeu, fWert, fZaehler, fNenner, nCount;
852 [ # # ]: 0 : if (fSchaetzwert == -1.0)
853 : 0 : x = 0.1; // default gegen Nulldivisionen
854 : : else
855 : 0 : x = fSchaetzwert; // Startwert
856 [ # # ][ # # ]: 0 : switch (GetStackType())
857 : : {
858 : : case svDoubleRef :
859 : 0 : break;
860 : : default:
861 : : {
862 [ # # ]: 0 : PushIllegalParameter();
863 : : return;
864 : : }
865 : : }
866 : 0 : const sal_uInt16 nIterationsMax = 20;
867 : 0 : sal_uInt16 nItCount = 0;
868 : 0 : ScRange aRange;
869 [ # # ][ # # ]: 0 : while (fEps > SCdEpsilon && nItCount < nIterationsMax)
[ # # ]
870 : : { // Newton-Verfahren:
871 : 0 : sp = sPos; // Stack zuruecksetzen
872 : 0 : nCount = 0.0;
873 : 0 : fZaehler = 0.0;
874 : 0 : fNenner = 0.0;
875 : 0 : sal_uInt16 nErr = 0;
876 [ # # ]: 0 : PopDoubleRef( aRange );
877 [ # # ]: 0 : ScValueIterator aValIter(pDok, aRange, glSubTotal);
878 [ # # ][ # # ]: 0 : if (aValIter.GetFirst(fWert, nErr))
879 : : {
880 : 0 : fZaehler += fWert / pow(1.0+x,(double)nCount);
881 : 0 : fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0);
882 : 0 : nCount++;
883 [ # # ][ # # ]: 0 : while ((nErr == 0) && aValIter.GetNext(fWert, nErr))
[ # # ][ # # ]
884 : : {
885 : 0 : fZaehler += fWert / pow(1.0+x,(double)nCount);
886 : 0 : fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0);
887 : 0 : nCount++;
888 : : }
889 : 0 : SetError(nErr);
890 : : }
891 : 0 : xNeu = x - fZaehler / fNenner; // x(i+1) = x(i)-f(x(i))/f'(x(i))
892 : 0 : nItCount++;
893 : 0 : fEps = fabs(xNeu - x);
894 : 0 : x = xNeu;
895 : : }
896 [ # # ][ # # ]: 0 : if (fSchaetzwert == 0.0 && fabs(x) < SCdEpsilon)
897 : 0 : x = 0.0; // auf Null normieren
898 [ # # ]: 0 : if (fEps < SCdEpsilon)
899 [ # # ]: 0 : PushDouble(x);
900 : : else
901 [ # # ]: 0 : PushError( errNoConvergence);
902 : : }
903 : :
904 : 0 : void ScInterpreter::ScMIRR()
905 : : { // range_of_values ; rate_invest ; rate_reinvest
906 : 0 : nFuncFmtType = NUMBERFORMAT_PERCENT;
907 [ # # ]: 0 : if( MustHaveParamCount( GetByte(), 3 ) )
908 : : {
909 [ # # ]: 0 : double fRate1_reinvest = GetDouble() + 1;
910 [ # # ]: 0 : double fRate1_invest = GetDouble() + 1;
911 : :
912 : 0 : ScRange aRange;
913 [ # # ]: 0 : PopDoubleRef( aRange );
914 : :
915 [ # # ]: 0 : if( nGlobalError )
916 [ # # ]: 0 : PushError( nGlobalError);
917 : : else
918 : : {
919 : 0 : double fNPV_reinvest = 0.0;
920 : 0 : double fPow_reinvest = 1.0;
921 : 0 : double fNPV_invest = 0.0;
922 : 0 : double fPow_invest = 1.0;
923 [ # # ]: 0 : ScValueIterator aValIter( pDok, aRange, glSubTotal );
924 : : double fCellValue;
925 : 0 : sal_uLong nCount = 0;
926 : 0 : sal_uInt16 nIterError = 0;
927 : :
928 [ # # ]: 0 : bool bLoop = aValIter.GetFirst( fCellValue, nIterError );
929 [ # # ]: 0 : while( bLoop )
930 : : {
931 [ # # ]: 0 : if( fCellValue > 0.0 ) // reinvestments
932 : 0 : fNPV_reinvest += fCellValue * fPow_reinvest;
933 [ # # ]: 0 : else if( fCellValue < 0.0 ) // investments
934 : 0 : fNPV_invest += fCellValue * fPow_invest;
935 : 0 : fPow_reinvest /= fRate1_reinvest;
936 : 0 : fPow_invest /= fRate1_invest;
937 : 0 : nCount++;
938 : :
939 [ # # ]: 0 : bLoop = aValIter.GetNext( fCellValue, nIterError );
940 : : }
941 [ # # ]: 0 : if( nIterError )
942 [ # # ]: 0 : PushError( nIterError );
943 : : else
944 : : {
945 : 0 : double fResult = -fNPV_reinvest / fNPV_invest;
946 : 0 : fResult *= pow( fRate1_reinvest, (double) nCount - 1 );
947 : 0 : fResult = pow( fResult, 1.0 / (nCount - 1) );
948 [ # # ]: 0 : PushDouble( fResult - 1.0 );
949 : : }
950 : : }
951 : : }
952 : 0 : }
953 : :
954 : :
955 : 0 : void ScInterpreter::ScISPMT()
956 : : { // rate ; period ; total_periods ; invest
957 [ # # ]: 0 : if( MustHaveParamCount( GetByte(), 4 ) )
958 : : {
959 : 0 : double fInvest = GetDouble();
960 : 0 : double fTotal = GetDouble();
961 : 0 : double fPeriod = GetDouble();
962 : 0 : double fRate = GetDouble();
963 : :
964 [ # # ]: 0 : if( nGlobalError )
965 : 0 : PushError( nGlobalError);
966 : : else
967 : 0 : PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) );
968 : : }
969 : 0 : }
970 : :
971 : :
972 : : //----------------------- Finanzfunktionen ------------------------------------
973 : :
974 : 0 : double ScInterpreter::ScGetBw(double fZins, double fZzr, double fRmz,
975 : : double fZw, double fF)
976 : : {
977 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMIRR" );
978 : : double fBw;
979 [ # # ]: 0 : if (fZins == 0.0)
980 : 0 : fBw = fZw + fRmz * fZzr;
981 [ # # ]: 0 : else if (fF > 0.0)
982 : 0 : fBw = (fZw * pow(1.0 + fZins, -fZzr))
983 : 0 : + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr + 1.0)) / fZins)
984 : 0 : + fRmz;
985 : : else
986 : 0 : fBw = (fZw * pow(1.0 + fZins, -fZzr))
987 : 0 : + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr)) / fZins);
988 : 0 : return -fBw;
989 : : }
990 : :
991 : 0 : void ScInterpreter::ScBW()
992 : : {
993 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBW" );
994 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
995 : 0 : double nRmz, nZzr, nZins, nZw = 0, nFlag = 0;
996 : 0 : sal_uInt8 nParamCount = GetByte();
997 [ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
998 : 0 : return;
999 [ # # ]: 0 : if (nParamCount == 5)
1000 : 0 : nFlag = GetDouble();
1001 [ # # ]: 0 : if (nParamCount >= 4)
1002 : 0 : nZw = GetDouble();
1003 : 0 : nRmz = GetDouble();
1004 : 0 : nZzr = GetDouble();
1005 : 0 : nZins = GetDouble();
1006 : 0 : PushDouble(ScGetBw(nZins, nZzr, nRmz, nZw, nFlag));
1007 : : }
1008 : :
1009 : 0 : void ScInterpreter::ScDIA()
1010 : : {
1011 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDIA" );
1012 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1013 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 4 ) )
1014 : : {
1015 : 0 : double nZr = GetDouble();
1016 : 0 : double nDauer = GetDouble();
1017 : 0 : double nRest = GetDouble();
1018 : 0 : double nWert = GetDouble();
1019 : : double nDia = ((nWert - nRest) * (nDauer - nZr + 1.0)) /
1020 : 0 : ((nDauer * (nDauer + 1.0)) / 2.0);
1021 : 0 : PushDouble(nDia);
1022 : : }
1023 : 0 : }
1024 : :
1025 : 0 : double ScInterpreter::ScGetGDA(double fWert, double fRest, double fDauer,
1026 : : double fPeriode, double fFaktor)
1027 : : {
1028 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetGDA" );
1029 : : double fGda, fZins, fAlterWert, fNeuerWert;
1030 : 0 : fZins = fFaktor / fDauer;
1031 [ # # ]: 0 : if (fZins >= 1.0)
1032 : : {
1033 : 0 : fZins = 1.0;
1034 [ # # ]: 0 : if (fPeriode == 1.0)
1035 : 0 : fAlterWert = fWert;
1036 : : else
1037 : 0 : fAlterWert = 0.0;
1038 : : }
1039 : : else
1040 : 0 : fAlterWert = fWert * pow(1.0 - fZins, fPeriode - 1.0);
1041 : 0 : fNeuerWert = fWert * pow(1.0 - fZins, fPeriode);
1042 : :
1043 [ # # ]: 0 : if (fNeuerWert < fRest)
1044 : 0 : fGda = fAlterWert - fRest;
1045 : : else
1046 : 0 : fGda = fAlterWert - fNeuerWert;
1047 [ # # ]: 0 : if (fGda < 0.0)
1048 : 0 : fGda = 0.0;
1049 : 0 : return fGda;
1050 : : }
1051 : :
1052 : 0 : void ScInterpreter::ScGDA()
1053 : : {
1054 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA" );
1055 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1056 : 0 : sal_uInt8 nParamCount = GetByte();
1057 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 4, 5 ) )
1058 : : {
1059 : : double nFaktor;
1060 [ # # ]: 0 : if (nParamCount == 5)
1061 : 0 : nFaktor = GetDouble();
1062 : : else
1063 : 0 : nFaktor = 2.0;
1064 : 0 : double nPeriode = GetDouble();
1065 : 0 : double nDauer = GetDouble();
1066 : 0 : double nRest = GetDouble();
1067 : 0 : double nWert = GetDouble();
1068 [ # # ][ # # ]: 0 : if (nWert < 0.0 || nRest < 0.0 || nFaktor <= 0.0 || nRest > nWert
[ # # ][ # # ]
[ # # ][ # # ]
1069 : : || nPeriode < 1.0 || nPeriode > nDauer)
1070 : 0 : PushIllegalArgument();
1071 : : else
1072 : 0 : PushDouble(ScGetGDA(nWert, nRest, nDauer, nPeriode, nFaktor));
1073 : : }
1074 : 0 : }
1075 : :
1076 : 0 : void ScInterpreter::ScGDA2()
1077 : : {
1078 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA2" );
1079 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1080 : 0 : sal_uInt8 nParamCount = GetByte();
1081 [ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
1082 : 0 : return ;
1083 : : double nMonate;
1084 [ # # ]: 0 : if (nParamCount == 4)
1085 : 0 : nMonate = 12.0;
1086 : : else
1087 : 0 : nMonate = ::rtl::math::approxFloor(GetDouble());
1088 : 0 : double nPeriode = GetDouble();
1089 : 0 : double nDauer = GetDouble();
1090 : 0 : double nRest = GetDouble();
1091 : 0 : double nWert = GetDouble();
1092 [ # # ][ # # ]: 0 : if (nMonate < 1.0 || nMonate > 12.0 || nDauer > 1200.0 || nRest < 0.0 ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1093 : : nPeriode > (nDauer + 1.0) || nRest > nWert || nWert < 0.0)
1094 : : {
1095 : 0 : PushIllegalArgument();
1096 : 0 : return;
1097 : : }
1098 : 0 : double nAbRate = 1.0 - pow(nRest / nWert, 1.0 / nDauer);
1099 : 0 : nAbRate = ::rtl::math::approxFloor((nAbRate * 1000.0) + 0.5) / 1000.0;
1100 : 0 : double nErsteAbRate = nWert * nAbRate * nMonate / 12.0;
1101 : 0 : double nGda2 = 0.0;
1102 [ # # ]: 0 : if (::rtl::math::approxFloor(nPeriode) == 1)
1103 : 0 : nGda2 = nErsteAbRate;
1104 : : else
1105 : : {
1106 : 0 : double nSummAbRate = nErsteAbRate;
1107 : 0 : double nMin = nDauer;
1108 [ # # ]: 0 : if (nMin > nPeriode) nMin = nPeriode;
1109 : 0 : sal_uInt16 iMax = (sal_uInt16)::rtl::math::approxFloor(nMin);
1110 [ # # ]: 0 : for (sal_uInt16 i = 2; i <= iMax; i++)
1111 : : {
1112 : 0 : nGda2 = (nWert - nSummAbRate) * nAbRate;
1113 : 0 : nSummAbRate += nGda2;
1114 : : }
1115 [ # # ]: 0 : if (nPeriode > nDauer)
1116 : 0 : nGda2 = ((nWert - nSummAbRate) * nAbRate * (12.0 - nMonate)) / 12.0;
1117 : : }
1118 : 0 : PushDouble(nGda2);
1119 : : }
1120 : :
1121 : :
1122 : 0 : double ScInterpreter::ScInterVDB(double fWert,double fRest,double fDauer,
1123 : : double fDauer1,double fPeriode,double fFaktor)
1124 : : {
1125 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInterVDB" );
1126 : 0 : double fVdb=0;
1127 : 0 : double fIntEnd = ::rtl::math::approxCeil(fPeriode);
1128 : 0 : sal_uLong nLoopEnd = (sal_uLong) fIntEnd;
1129 : :
1130 : : double fTerm, fLia;
1131 : 0 : double fRestwert = fWert - fRest;
1132 : 0 : bool bNowLia = false;
1133 : :
1134 : : double fGda;
1135 : : sal_uLong i;
1136 : 0 : fLia=0;
1137 [ # # ]: 0 : for ( i = 1; i <= nLoopEnd; i++)
1138 : : {
1139 [ # # ]: 0 : if(!bNowLia)
1140 : : {
1141 : 0 : fGda = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
1142 : 0 : fLia = fRestwert/ (fDauer1 - (double) (i-1));
1143 : :
1144 [ # # ]: 0 : if (fLia > fGda)
1145 : : {
1146 : 0 : fTerm = fLia;
1147 : 0 : bNowLia = true;
1148 : : }
1149 : : else
1150 : : {
1151 : 0 : fTerm = fGda;
1152 : 0 : fRestwert -= fGda;
1153 : : }
1154 : : }
1155 : : else
1156 : : {
1157 : 0 : fTerm = fLia;
1158 : : }
1159 : :
1160 [ # # ]: 0 : if ( i == nLoopEnd)
1161 : 0 : fTerm *= ( fPeriode + 1.0 - fIntEnd );
1162 : :
1163 : 0 : fVdb += fTerm;
1164 : : }
1165 : 0 : return fVdb;
1166 : : }
1167 : :
1168 : :
1169 : 0 : inline double DblMin( double a, double b )
1170 : : {
1171 [ # # ]: 0 : return (a < b) ? a : b;
1172 : : }
1173 : :
1174 : 0 : void ScInterpreter::ScVDB()
1175 : : {
1176 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVDB" );
1177 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1178 : 0 : sal_uInt8 nParamCount = GetByte();
1179 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 5, 7 ) )
1180 : : {
1181 : 0 : double fWert, fRest, fDauer, fAnfang, fEnde, fFaktor, fVdb = 0.0;
1182 : : bool bFlag;
1183 [ # # ]: 0 : if (nParamCount == 7)
1184 : 0 : bFlag = GetBool();
1185 : : else
1186 : 0 : bFlag = false;
1187 [ # # ]: 0 : if (nParamCount >= 6)
1188 : 0 : fFaktor = GetDouble();
1189 : : else
1190 : 0 : fFaktor = 2.0;
1191 : 0 : fEnde = GetDouble();
1192 : 0 : fAnfang = GetDouble();
1193 : 0 : fDauer = GetDouble();
1194 : 0 : fRest = GetDouble();
1195 : 0 : fWert = GetDouble();
1196 [ # # ][ # # ]: 0 : if (fAnfang < 0.0 || fEnde < fAnfang || fEnde > fDauer || fWert < 0.0
[ # # ][ # # ]
[ # # ][ # # ]
1197 : : || fRest > fWert || fFaktor <= 0.0)
1198 : 0 : PushIllegalArgument();
1199 : : else
1200 : : {
1201 : 0 : double fIntStart = ::rtl::math::approxFloor(fAnfang);
1202 : 0 : double fIntEnd = ::rtl::math::approxCeil(fEnde);
1203 : 0 : sal_uLong nLoopStart = (sal_uLong) fIntStart;
1204 : 0 : sal_uLong nLoopEnd = (sal_uLong) fIntEnd;
1205 : :
1206 : 0 : fVdb = 0.0;
1207 [ # # ]: 0 : if (bFlag)
1208 : : {
1209 [ # # ]: 0 : for (sal_uLong i = nLoopStart + 1; i <= nLoopEnd; i++)
1210 : : {
1211 : 0 : double fTerm = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor);
1212 : :
1213 : : // Teilperioden am Anfang / Ende beruecksichtigen:
1214 [ # # ]: 0 : if ( i == nLoopStart+1 )
1215 : 0 : fTerm *= ( DblMin( fEnde, fIntStart + 1.0 ) - fAnfang );
1216 [ # # ]: 0 : else if ( i == nLoopEnd )
1217 : 0 : fTerm *= ( fEnde + 1.0 - fIntEnd );
1218 : :
1219 : 0 : fVdb += fTerm;
1220 : : }
1221 : : }
1222 : : else
1223 : : {
1224 : :
1225 : 0 : double fDauer1=fDauer;
1226 : :
1227 : : //@Die Frage aller Fragen: "Ist das hier richtig"
1228 [ # # ]: 0 : if(!::rtl::math::approxEqual(fAnfang,::rtl::math::approxFloor(fAnfang)))
1229 : : {
1230 [ # # ]: 0 : if(fFaktor>1)
1231 : : {
1232 [ # # ][ # # ]: 0 : if(fAnfang>fDauer/2 || ::rtl::math::approxEqual(fAnfang,fDauer/2))
[ # # ]
1233 : : {
1234 : 0 : double fPart=fAnfang-fDauer/2;
1235 : 0 : fAnfang=fDauer/2;
1236 : 0 : fEnde-=fPart;
1237 : 0 : fDauer1+=1;
1238 : : }
1239 : : }
1240 : : }
1241 : :
1242 : 0 : fWert-=ScInterVDB(fWert,fRest,fDauer,fDauer1,fAnfang,fFaktor);
1243 : 0 : fVdb=ScInterVDB(fWert,fRest,fDauer,fDauer-fAnfang,fEnde-fAnfang,fFaktor);
1244 : : }
1245 : : }
1246 : 0 : PushDouble(fVdb);
1247 : : }
1248 : 0 : }
1249 : :
1250 : 0 : void ScInterpreter::ScLaufz()
1251 : : {
1252 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLaufz" );
1253 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
1254 : : {
1255 : 0 : double nZukunft = GetDouble();
1256 : 0 : double nGegenwart = GetDouble();
1257 : 0 : double nZins = GetDouble();
1258 : 0 : PushDouble(log(nZukunft / nGegenwart) / log(1.0 + nZins));
1259 : : }
1260 : 0 : }
1261 : :
1262 : 0 : void ScInterpreter::ScLIA()
1263 : : {
1264 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLIA" );
1265 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1266 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
1267 : : {
1268 : 0 : double nDauer = GetDouble();
1269 : 0 : double nRest = GetDouble();
1270 : 0 : double nWert = GetDouble();
1271 : 0 : PushDouble((nWert - nRest) / nDauer);
1272 : : }
1273 : 0 : }
1274 : :
1275 : 0 : double ScInterpreter::ScGetRmz(double fRate, double fNper, double fPv,
1276 : : double fFv, double fPaytype)
1277 : : {
1278 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetRmz" );
1279 : : double fPayment;
1280 [ # # ]: 0 : if (fRate == 0.0)
1281 : 0 : fPayment = (fPv + fFv) / fNper;
1282 : : else
1283 : : {
1284 [ # # ]: 0 : if (fPaytype > 0.0) // payment in advance
1285 : 0 : fPayment = (fFv + fPv * exp( fNper * ::rtl::math::log1p(fRate) ) ) * fRate /
1286 : 0 : (::rtl::math::expm1( (fNper + 1) * ::rtl::math::log1p(fRate) ) - fRate);
1287 : : else // payment in arrear
1288 : 0 : fPayment = (fFv + fPv * exp(fNper * ::rtl::math::log1p(fRate) ) ) * fRate /
1289 : 0 : ::rtl::math::expm1( fNper * ::rtl::math::log1p(fRate) );
1290 : : }
1291 : 0 : return -fPayment;
1292 : : }
1293 : :
1294 : 0 : void ScInterpreter::ScRMZ()
1295 : : {
1296 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRMZ" );
1297 : 0 : double nZins, nZzr, nBw, nZw = 0, nFlag = 0;
1298 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1299 : 0 : sal_uInt8 nParamCount = GetByte();
1300 [ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1301 : 0 : return;
1302 [ # # ]: 0 : if (nParamCount == 5)
1303 : 0 : nFlag = GetDouble();
1304 [ # # ]: 0 : if (nParamCount >= 4)
1305 : 0 : nZw = GetDouble();
1306 : 0 : nBw = GetDouble();
1307 : 0 : nZzr = GetDouble();
1308 : 0 : nZins = GetDouble();
1309 : 0 : PushDouble(ScGetRmz(nZins, nZzr, nBw, nZw, nFlag));
1310 : : }
1311 : :
1312 : 0 : void ScInterpreter::ScZGZ()
1313 : : {
1314 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZGZ" );
1315 : 0 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1316 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
1317 : : {
1318 : 0 : double nZukunftswert = GetDouble();
1319 : 0 : double nGegenwartswert = GetDouble();
1320 : 0 : double nZeitraum = GetDouble();
1321 : 0 : PushDouble(pow(nZukunftswert / nGegenwartswert, 1.0 / nZeitraum) - 1.0);
1322 : : }
1323 : 0 : }
1324 : :
1325 : 0 : double ScInterpreter::ScGetZw(double fZins, double fZzr, double fRmz,
1326 : : double fBw, double fF)
1327 : : {
1328 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZw" );
1329 : : double fZw;
1330 [ # # ]: 0 : if (fZins == 0.0)
1331 : 0 : fZw = fBw + fRmz * fZzr;
1332 : : else
1333 : : {
1334 : 0 : double fTerm = pow(1.0 + fZins, fZzr);
1335 [ # # ]: 0 : if (fF > 0.0)
1336 : 0 : fZw = fBw * fTerm + fRmz*(1.0 + fZins)*(fTerm - 1.0)/fZins;
1337 : : else
1338 : 0 : fZw = fBw * fTerm + fRmz*(fTerm - 1.0)/fZins;
1339 : : }
1340 : 0 : return -fZw;
1341 : : }
1342 : :
1343 : 0 : void ScInterpreter::ScZW()
1344 : : {
1345 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZW" );
1346 : 0 : double nZins, nZzr, nRmz, nBw = 0, nFlag = 0;
1347 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1348 : 0 : sal_uInt8 nParamCount = GetByte();
1349 [ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1350 : 0 : return;
1351 [ # # ]: 0 : if (nParamCount == 5)
1352 : 0 : nFlag = GetDouble();
1353 [ # # ]: 0 : if (nParamCount >= 4)
1354 : 0 : nBw = GetDouble();
1355 : 0 : nRmz = GetDouble();
1356 : 0 : nZzr = GetDouble();
1357 : 0 : nZins = GetDouble();
1358 : 0 : PushDouble(ScGetZw(nZins, nZzr, nRmz, nBw, nFlag));
1359 : : }
1360 : :
1361 : 0 : void ScInterpreter::ScZZR()
1362 : : {
1363 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZZR" );
1364 : 0 : double nZins, nRmz, nBw, nZw = 0, nFlag = 0;
1365 : 0 : sal_uInt8 nParamCount = GetByte();
1366 [ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1367 : 0 : return;
1368 [ # # ]: 0 : if (nParamCount == 5)
1369 : 0 : nFlag = GetDouble();
1370 [ # # ]: 0 : if (nParamCount >= 4)
1371 : 0 : nZw = GetDouble();
1372 : 0 : nBw = GetDouble();
1373 : 0 : nRmz = GetDouble();
1374 : 0 : nZins = GetDouble();
1375 [ # # ]: 0 : if (nZins == 0.0)
1376 : 0 : PushDouble(-(nBw + nZw)/nRmz);
1377 [ # # ]: 0 : else if (nFlag > 0.0)
1378 : 0 : PushDouble(log(-(nZins*nZw-nRmz*(1.0+nZins))/(nZins*nBw+nRmz*(1.0+nZins)))
1379 : 0 : /log(1.0+nZins));
1380 : : else
1381 : 0 : PushDouble(log(-(nZins*nZw-nRmz)/(nZins*nBw+nRmz))/log(1.0+nZins));
1382 : : }
1383 : :
1384 : 0 : bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv,
1385 : : double fFv, double fPayType, double & fGuess )
1386 : : {
1387 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RateIteration" );
1388 : : // See also #i15090#
1389 : : // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
1390 : : // This solution handles integer and non-integer values of Nper different.
1391 : : // If ODFF will constraint Nper to integer, the distinction of cases can be
1392 : : // removed; only the integer-part is needed then.
1393 : 0 : bool bValid = true, bFound = false;
1394 : : double fX, fXnew, fTerm, fTermDerivation;
1395 : : double fGeoSeries, fGeoSeriesDerivation;
1396 : 0 : const sal_uInt16 nIterationsMax = 150;
1397 : 0 : sal_uInt16 nCount = 0;
1398 : 0 : const double fEpsilonSmall = 1.0E-14;
1399 : : // convert any fPayType situation to fPayType == zero situation
1400 : 0 : fFv = fFv - fPayment * fPayType;
1401 : 0 : fPv = fPv + fPayment * fPayType;
1402 [ # # ]: 0 : if (fNper == ::rtl::math::round( fNper, 0, rtl_math_RoundingMode_Corrected ))
1403 : : { // Nper is an integer value
1404 : 0 : fX = fGuess;
1405 : : double fPowN, fPowNminus1; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
1406 [ # # ][ # # ]: 0 : while (!bFound && nCount < nIterationsMax)
[ # # ]
1407 : : {
1408 : 0 : fPowNminus1 = pow( 1.0+fX, fNper-1.0);
1409 : 0 : fPowN = fPowNminus1 * (1.0+fX);
1410 [ # # ]: 0 : if (rtl::math::approxEqual( fabs(fX), 0.0))
1411 : : {
1412 : 0 : fGeoSeries = fNper;
1413 : 0 : fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1414 : : }
1415 : : else
1416 : : {
1417 : 0 : fGeoSeries = (fPowN-1.0)/fX;
1418 : 0 : fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;
1419 : : }
1420 : 0 : fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;
1421 : 0 : fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;
1422 [ # # ]: 0 : if (fabs(fTerm) < fEpsilonSmall)
1423 : 0 : bFound = true; // will catch root which is at an extreme
1424 : : else
1425 : : {
1426 [ # # ]: 0 : if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1427 : 0 : fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
1428 : : else
1429 : 0 : fXnew = fX - fTerm / fTermDerivation;
1430 : 0 : nCount++;
1431 : : // more accuracy not possible in oscillating cases
1432 : 0 : bFound = (fabs(fXnew - fX) < SCdEpsilon);
1433 : 0 : fX = fXnew;
1434 : : }
1435 : : }
1436 : : // Gnumeric returns roots < -1, Excel gives an error in that cases,
1437 : : // ODFF says nothing about it. Enable the statement, if you want Excel's
1438 : : // behavior
1439 : : //bValid =(fX >=-1.0);
1440 : : }
1441 : : else
1442 : : { // Nper is not an integer value.
1443 [ # # ]: 0 : fX = (fGuess < -1.0) ? -1.0 : fGuess; // start with a valid fX
1444 [ # # ][ # # ]: 0 : while (bValid && !bFound && nCount < nIterationsMax)
[ # # ][ # # ]
1445 : : {
1446 [ # # ]: 0 : if (rtl::math::approxEqual( fabs(fX), 0.0))
1447 : : {
1448 : 0 : fGeoSeries = fNper;
1449 : 0 : fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1450 : : }
1451 : : else
1452 : : {
1453 : 0 : fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;
1454 : 0 : fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;
1455 : : }
1456 : 0 : fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;
1457 : 0 : fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;
1458 [ # # ]: 0 : if (fabs(fTerm) < fEpsilonSmall)
1459 : 0 : bFound = true; // will catch root which is at an extreme
1460 : : else
1461 : : {
1462 [ # # ]: 0 : if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1463 : 0 : fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
1464 : : else
1465 : 0 : fXnew = fX - fTerm / fTermDerivation;
1466 : 0 : nCount++;
1467 : : // more accuracy not possible in oscillating cases
1468 : 0 : bFound = (fabs(fXnew - fX) < SCdEpsilon);
1469 : 0 : fX = fXnew;
1470 : 0 : bValid = (fX >= -1.0); // otherwise pow(1.0+fX,fNper) will fail
1471 : : }
1472 : : }
1473 : : }
1474 : 0 : fGuess = fX; // return approximate root
1475 [ # # ][ # # ]: 0 : return bValid && bFound;
1476 : : }
1477 : :
1478 : : // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
1479 : 0 : void ScInterpreter::ScZins()
1480 : : {
1481 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZins" );
1482 : : double fPv, fPayment, fNper;
1483 : : // defaults for missing arguments, see ODFF spec
1484 : 0 : double fFv = 0, fPayType = 0, fGuess = 0.1;
1485 : 0 : bool bValid = true;
1486 : 0 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1487 : 0 : sal_uInt8 nParamCount = GetByte();
1488 [ # # ][ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 3, 6 ) )
1489 : : return;
1490 [ # # ]: 0 : if (nParamCount == 6)
1491 [ # # ]: 0 : fGuess = GetDouble();
1492 [ # # ]: 0 : if (nParamCount >= 5)
1493 [ # # ]: 0 : fPayType = GetDouble();
1494 [ # # ]: 0 : if (nParamCount >= 4)
1495 [ # # ]: 0 : fFv = GetDouble();
1496 [ # # ]: 0 : fPv = GetDouble();
1497 [ # # ]: 0 : fPayment = GetDouble();
1498 [ # # ]: 0 : fNper = GetDouble();
1499 [ # # ]: 0 : if (fNper <= 0.0) // constraint from ODFF spec
1500 : : {
1501 [ # # ]: 0 : PushIllegalArgument();
1502 : : return;
1503 : : }
1504 : : // other values for fPayType might be meaningful,
1505 : : // ODFF spec is not clear yet, enable statement if you want only 0 and 1
1506 : : //if (fPayType != 0.0) fPayType = 1.0;
1507 : 0 : bValid = RateIteration(fNper, fPayment, fPv, fFv, fPayType, fGuess);
1508 [ # # ]: 0 : if (!bValid)
1509 : 0 : SetError(errNoConvergence);
1510 [ # # ]: 0 : PushDouble(fGuess);
1511 : : }
1512 : :
1513 : 0 : double ScInterpreter::ScGetZinsZ(double fZins, double fZr, double fZzr, double fBw,
1514 : : double fZw, double fF, double& fRmz)
1515 : : {
1516 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZinsZ" );
1517 : 0 : fRmz = ScGetRmz(fZins, fZzr, fBw, fZw, fF); // fuer kapz auch bei fZr == 1
1518 : : double fZinsZ;
1519 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1520 [ # # ]: 0 : if (fZr == 1.0)
1521 : : {
1522 [ # # ]: 0 : if (fF > 0.0)
1523 : 0 : fZinsZ = 0.0;
1524 : : else
1525 : 0 : fZinsZ = -fBw;
1526 : : }
1527 : : else
1528 : : {
1529 [ # # ]: 0 : if (fF > 0.0)
1530 : 0 : fZinsZ = ScGetZw(fZins, fZr-2.0, fRmz, fBw, 1.0) - fRmz;
1531 : : else
1532 : 0 : fZinsZ = ScGetZw(fZins, fZr-1.0, fRmz, fBw, 0.0);
1533 : : }
1534 : 0 : return fZinsZ * fZins;
1535 : : }
1536 : :
1537 : 0 : void ScInterpreter::ScZinsZ()
1538 : : {
1539 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZinsZ" );
1540 : 0 : double nZins, nZr, nZzr, nBw, nZw = 0, nFlag = 0;
1541 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1542 : 0 : sal_uInt8 nParamCount = GetByte();
1543 [ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1544 : 0 : return;
1545 [ # # ]: 0 : if (nParamCount == 6)
1546 : 0 : nFlag = GetDouble();
1547 [ # # ]: 0 : if (nParamCount >= 5)
1548 : 0 : nZw = GetDouble();
1549 : 0 : nBw = GetDouble();
1550 : 0 : nZzr = GetDouble();
1551 : 0 : nZr = GetDouble();
1552 : 0 : nZins = GetDouble();
1553 [ # # ][ # # ]: 0 : if (nZr < 1.0 || nZr > nZzr)
1554 : 0 : PushIllegalArgument();
1555 : : else
1556 : : {
1557 : : double nRmz;
1558 [ # # ]: 0 : PushDouble(ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz));
1559 : : }
1560 : : }
1561 : :
1562 : 0 : void ScInterpreter::ScKapz()
1563 : : {
1564 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKapz" );
1565 : 0 : double nZins, nZr, nZzr, nBw, nZw = 0, nFlag = 0;
1566 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1567 : 0 : sal_uInt8 nParamCount = GetByte();
1568 [ # # ]: 0 : if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1569 : 0 : return;
1570 [ # # ]: 0 : if (nParamCount == 6)
1571 : 0 : nFlag = GetDouble();
1572 [ # # ]: 0 : if (nParamCount >= 5)
1573 : 0 : nZw = GetDouble();
1574 : 0 : nBw = GetDouble();
1575 : 0 : nZzr = GetDouble();
1576 : 0 : nZr = GetDouble();
1577 : 0 : nZins = GetDouble();
1578 [ # # ][ # # ]: 0 : if (nZr < 1.0 || nZr > nZzr)
1579 : 0 : PushIllegalArgument();
1580 : : else
1581 : : {
1582 : : double nRmz;
1583 : 0 : double nZinsz = ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz);
1584 [ # # ]: 0 : PushDouble(nRmz - nZinsz);
1585 : : }
1586 : : }
1587 : :
1588 : 0 : void ScInterpreter::ScKumZinsZ()
1589 : : {
1590 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumZinsZ" );
1591 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1592 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 6 ) )
1593 : : {
1594 : : double fZins, fZzr, fBw, fAnfang, fEnde, fF;
1595 : 0 : fF = GetDouble();
1596 : 0 : fEnde = ::rtl::math::approxFloor(GetDouble());
1597 : 0 : fAnfang = ::rtl::math::approxFloor(GetDouble());
1598 : 0 : fBw = GetDouble();
1599 : 0 : fZzr = GetDouble();
1600 : 0 : fZins = GetDouble();
1601 [ # # ][ # # ]: 0 : if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
[ # # ][ # # ]
[ # # ][ # # ]
1602 : : fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0)
1603 : 0 : PushIllegalArgument();
1604 : : else
1605 : : {
1606 : 0 : sal_uLong nAnfang = (sal_uLong) fAnfang;
1607 : 0 : sal_uLong nEnde = (sal_uLong) fEnde ;
1608 : 0 : double fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
1609 : 0 : double fZinsZ = 0.0;
1610 [ # # ]: 0 : if (nAnfang == 1)
1611 : : {
1612 [ # # ]: 0 : if (fF <= 0.0)
1613 : 0 : fZinsZ = -fBw;
1614 : 0 : nAnfang++;
1615 : : }
1616 [ # # ]: 0 : for (sal_uLong i = nAnfang; i <= nEnde; i++)
1617 : : {
1618 [ # # ]: 0 : if (fF > 0.0)
1619 : 0 : fZinsZ += ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz;
1620 : : else
1621 : 0 : fZinsZ += ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0);
1622 : : }
1623 : 0 : fZinsZ *= fZins;
1624 : 0 : PushDouble(fZinsZ);
1625 : : }
1626 : : }
1627 : 0 : }
1628 : :
1629 : 0 : void ScInterpreter::ScKumKapZ()
1630 : : {
1631 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumKapZ" );
1632 : 0 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1633 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 6 ) )
1634 : : {
1635 : : double fZins, fZzr, fBw, fAnfang, fEnde, fF;
1636 : 0 : fF = GetDouble();
1637 : 0 : fEnde = ::rtl::math::approxFloor(GetDouble());
1638 : 0 : fAnfang = ::rtl::math::approxFloor(GetDouble());
1639 : 0 : fBw = GetDouble();
1640 : 0 : fZzr = GetDouble();
1641 : 0 : fZins = GetDouble();
1642 [ # # ][ # # ]: 0 : if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 ||
[ # # ][ # # ]
[ # # ][ # # ]
1643 : : fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0)
1644 : 0 : PushIllegalArgument();
1645 : : else
1646 : : {
1647 : 0 : double fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF);
1648 : 0 : double fKapZ = 0.0;
1649 : 0 : sal_uLong nAnfang = (sal_uLong) fAnfang;
1650 : 0 : sal_uLong nEnde = (sal_uLong) fEnde;
1651 [ # # ]: 0 : if (nAnfang == 1)
1652 : : {
1653 [ # # ]: 0 : if (fF <= 0.0)
1654 : 0 : fKapZ = fRmz + fBw * fZins;
1655 : : else
1656 : 0 : fKapZ = fRmz;
1657 : 0 : nAnfang++;
1658 : : }
1659 [ # # ]: 0 : for (sal_uLong i = nAnfang; i <= nEnde; i++)
1660 : : {
1661 [ # # ]: 0 : if (fF > 0.0)
1662 : 0 : fKapZ += fRmz - (ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz) * fZins;
1663 : : else
1664 : 0 : fKapZ += fRmz - ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0) * fZins;
1665 : : }
1666 : 0 : PushDouble(fKapZ);
1667 : : }
1668 : : }
1669 : 0 : }
1670 : :
1671 : 0 : void ScInterpreter::ScEffektiv()
1672 : : {
1673 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEffektiv" );
1674 : 0 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1675 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
1676 : : {
1677 : 0 : double fPerioden = GetDouble();
1678 : 0 : double fNominal = GetDouble();
1679 [ # # ][ # # ]: 0 : if (fPerioden < 1.0 || fNominal <= 0.0)
1680 : 0 : PushIllegalArgument();
1681 : : else
1682 : : {
1683 : 0 : fPerioden = ::rtl::math::approxFloor(fPerioden);
1684 : 0 : PushDouble(pow(1.0 + fNominal/fPerioden, fPerioden) - 1.0);
1685 : : }
1686 : : }
1687 : 0 : }
1688 : :
1689 : 0 : void ScInterpreter::ScNominal()
1690 : : {
1691 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNominal" );
1692 : 0 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1693 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
1694 : : {
1695 : 0 : double fPerioden = GetDouble();
1696 : 0 : double fEffektiv = GetDouble();
1697 [ # # ][ # # ]: 0 : if (fPerioden < 1.0 || fEffektiv <= 0.0)
1698 : 0 : PushIllegalArgument();
1699 : : else
1700 : : {
1701 : 0 : fPerioden = ::rtl::math::approxFloor(fPerioden);
1702 : 0 : PushDouble( (pow(fEffektiv + 1.0, 1.0 / fPerioden) - 1.0) * fPerioden );
1703 : : }
1704 : : }
1705 : 0 : }
1706 : :
1707 : 0 : void ScInterpreter::ScMod()
1708 : : {
1709 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMod" );
1710 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
1711 : : {
1712 : 0 : double fVal2 = GetDouble(); // Denominator
1713 : 0 : double fVal1 = GetDouble(); // Numerator
1714 [ # # ]: 0 : if (fVal2 == floor(fVal2)) // a pure integral number stored in double
1715 : : {
1716 : 0 : double fResult = fmod(fVal1,fVal2);
1717 [ # # ][ # # ]: 0 : if ( (fResult != 0.0) &&
[ # # ][ # # ]
[ # # ]
1718 : : ((fVal1 > 0.0 && fVal2 < 0.0) || (fVal1 < 0.0 && fVal2 > 0.0)))
1719 : 0 : fResult += fVal2 ;
1720 : 0 : PushDouble( fResult );
1721 : : }
1722 : : else
1723 : : {
1724 : : PushDouble( ::rtl::math::approxSub( fVal1,
1725 : 0 : ::rtl::math::approxFloor(fVal1 / fVal2) * fVal2));
1726 : : }
1727 : : }
1728 : 0 : }
1729 : :
1730 : : /** (Goal Seek) Find a value of x that is a root of f(x)
1731 : :
1732 : : This function is used internally for the goal seek operation. It uses the
1733 : : Regula Falsi (aka false position) algorithm to find a root of f(x). The
1734 : : start value and the target value are to be given by the user in the
1735 : : goal seek dialog. The f(x) in this case is defined as the formula in the
1736 : : formula cell minus target value. This function may also perform additional
1737 : : search in the horizontal directions when the f(x) is discrete in order to
1738 : : ensure a non-zero slope necessary for deriving a subsequent x that is
1739 : : reasonably close to the root of interest.
1740 : :
1741 : : @change 24.10.2004 by Kohei Yoshida (kohei@openoffice.org)
1742 : :
1743 : : @see #i28955#
1744 : : */
1745 : 3 : void ScInterpreter::ScBackSolver()
1746 : : {
1747 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBackSolver" );
1748 [ + - ]: 3 : if ( MustHaveParamCount( GetByte(), 3 ) )
1749 : : {
1750 : 3 : bool bDoneIteration = false;
1751 : 3 : ScAddress aValueAdr, aFormulaAdr;
1752 [ + - ]: 3 : double fTargetVal = GetDouble();
1753 [ + - ]: 3 : PopSingleRef( aFormulaAdr );
1754 [ + - ]: 3 : PopSingleRef( aValueAdr );
1755 : :
1756 [ + - ]: 3 : if (nGlobalError == 0)
1757 : : {
1758 [ + - ]: 3 : ScBaseCell* pVCell = GetCell( aValueAdr );
1759 : : // CELLTYPE_NOTE: kein Value aber von Formel referiert
1760 [ + - ]: 3 : ScBaseCell* pFCell = GetCell( aFormulaAdr );
1761 : :
1762 [ + - ][ + - ]: 6 : if ( ((pVCell && pVCell->GetCellType() == CELLTYPE_VALUE))
[ + - + - ]
[ + - ]
1763 : 3 : && pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA )
1764 : : {
1765 : 3 : ScRange aVRange( aValueAdr, aValueAdr ); // fuer SetDirty
1766 : : double fSaveVal; // Original value to be restored later if necessary
1767 : :
1768 [ + - ]: 3 : fSaveVal = GetCellValue( aValueAdr, pVCell );
1769 : :
1770 : 3 : const sal_uInt16 nMaxIter = 100;
1771 : 3 : const double fEps = 1E-10;
1772 : 3 : const double fDelta = 1E-6;
1773 : :
1774 : : double fBestX, fXPrev;
1775 : : double fBestF, fFPrev;
1776 : 3 : fBestX = fXPrev = fSaveVal;
1777 : :
1778 [ + - ]: 3 : ScFormulaCell* pFormula = (ScFormulaCell*) pFCell;
1779 : 3 : ScValueCell* pValue = (ScValueCell*) pVCell;
1780 : :
1781 [ + - ]: 3 : pFormula->Interpret();
1782 [ + - ]: 3 : bool bError = ( pFormula->GetErrCode() != 0 );
1783 : : // bError always corresponds with fF
1784 : :
1785 [ + - ]: 3 : fFPrev = pFormula->GetValue() - fTargetVal;
1786 : :
1787 : 3 : fBestF = fabs( fFPrev );
1788 [ - + ]: 3 : if ( fBestF < fDelta )
1789 : 0 : bDoneIteration = true;
1790 : :
1791 : 3 : double fX = fXPrev + fEps;
1792 : 3 : double fF = fFPrev;
1793 : : double fSlope;
1794 : :
1795 : 3 : sal_uInt16 nIter = 0;
1796 : :
1797 : 3 : bool bHorMoveError = false;
1798 : : // Nach der Regula Falsi Methode
1799 [ + + ][ + + ]: 118 : while ( !bDoneIteration && ( nIter++ < nMaxIter ) )
[ + + ]
1800 : : {
1801 : 115 : pValue->SetValue( fX );
1802 [ + - ]: 115 : pDok->SetDirty( aVRange );
1803 [ + - ]: 115 : pFormula->Interpret();
1804 [ + - ]: 115 : bError = ( pFormula->GetErrCode() != 0 );
1805 [ + - ]: 115 : fF = pFormula->GetValue() - fTargetVal;
1806 : :
1807 [ - + ][ # # ]: 115 : if ( fF == fFPrev && !bError )
1808 : : {
1809 : : // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x)
1810 : : // becomes different from the previous f(x). This routine is needed
1811 : : // when a given function is discrete, in which case the resulting slope
1812 : : // may become zero which ultimately causes the goal seek operation
1813 : : // to fail. #i28955#
1814 : :
1815 : 0 : sal_uInt16 nHorIter = 0;
1816 : 0 : const double fHorStepAngle = 5.0;
1817 : 0 : const double fHorMaxAngle = 80.0;
1818 : 0 : int nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle );
1819 : 0 : bool bDoneHorMove = false;
1820 : :
1821 [ # # ][ # # ]: 0 : while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
[ # # ][ # # ]
1822 : : {
1823 : 0 : double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
1824 : 0 : double fHorTangent = ::rtl::math::tan( fHorAngle * F_PI / 180 );
1825 : :
1826 : 0 : sal_uInt16 nIdx = 0;
1827 [ # # ][ # # ]: 0 : while( nIdx++ < 2 && !bDoneHorMove )
[ # # ]
1828 : : {
1829 : : double fHorX;
1830 [ # # ]: 0 : if ( nIdx == 1 )
1831 : 0 : fHorX = fX + fabs(fF)*fHorTangent;
1832 : : else
1833 : 0 : fHorX = fX - fabs(fF)*fHorTangent;
1834 : :
1835 : 0 : pValue->SetValue( fHorX );
1836 [ # # ]: 0 : pDok->SetDirty( aVRange );
1837 [ # # ]: 0 : pFormula->Interpret();
1838 [ # # ]: 0 : bHorMoveError = ( pFormula->GetErrCode() != 0 );
1839 [ # # ]: 0 : if ( bHorMoveError )
1840 : 0 : break;
1841 : :
1842 [ # # ]: 0 : fF = pFormula->GetValue() - fTargetVal;
1843 [ # # ]: 0 : if ( fF != fFPrev )
1844 : : {
1845 : 0 : fX = fHorX;
1846 : 0 : bDoneHorMove = true;
1847 : : }
1848 : : }
1849 : : }
1850 [ # # ]: 0 : if ( !bDoneHorMove )
1851 : 0 : bHorMoveError = true;
1852 : : }
1853 : :
1854 [ + + ]: 115 : if ( bError )
1855 : : {
1856 : : // move closer to last valid value (fXPrev), keep fXPrev & fFPrev
1857 : 93 : double fDiff = ( fXPrev - fX ) / 2;
1858 [ - + ]: 93 : if (fabs(fDiff) < fEps)
1859 [ # # ]: 0 : fDiff = (fDiff < 0.0) ? - fEps : fEps;
1860 : 93 : fX += fDiff;
1861 : : }
1862 [ - + ]: 22 : else if ( bHorMoveError )
1863 : 0 : break;
1864 [ + + ]: 22 : else if ( fabs(fF) < fDelta )
1865 : : {
1866 : : // converged to root
1867 : 2 : fBestX = fX;
1868 : 2 : bDoneIteration = true;
1869 : : }
1870 : : else
1871 : : {
1872 [ + + ]: 20 : if ( fabs(fF) + fDelta < fBestF )
1873 : : {
1874 : 17 : fBestX = fX;
1875 : 17 : fBestF = fabs(fF);
1876 : : }
1877 : :
1878 [ + - ]: 20 : if ( ( fXPrev - fX ) != 0 )
1879 : : {
1880 : 20 : fSlope = ( fFPrev - fF ) / ( fXPrev - fX );
1881 [ - + ]: 20 : if ( fabs( fSlope ) < fEps )
1882 [ # # ]: 0 : fSlope = fSlope < 0.0 ? -fEps : fEps;
1883 : : }
1884 : : else
1885 : 0 : fSlope = fEps;
1886 : :
1887 : 20 : fXPrev = fX;
1888 : 20 : fFPrev = fF;
1889 : 20 : fX = fX - ( fF / fSlope );
1890 : : }
1891 : : }
1892 : :
1893 : : // Try a nice rounded input value if possible.
1894 [ + + ][ + - ]: 3 : const double fNiceDelta = (bDoneIteration && fabs(fBestX) >= 1e-3 ? 1e-3 : fDelta);
1895 : 3 : double nX = ::rtl::math::approxFloor((fBestX / fNiceDelta) + 0.5) * fNiceDelta;
1896 : :
1897 [ + + ]: 3 : if ( bDoneIteration )
1898 : : {
1899 : 2 : pValue->SetValue( nX );
1900 [ + - ]: 2 : pDok->SetDirty( aVRange );
1901 [ + - ]: 2 : pFormula->Interpret();
1902 [ + - ][ + + ]: 2 : if ( fabs( pFormula->GetValue() - fTargetVal ) > fabs( fF ) )
1903 : 1 : nX = fBestX;
1904 : : }
1905 [ - + ][ # # ]: 1 : else if ( bError || bHorMoveError )
1906 : : {
1907 : 1 : nX = fBestX;
1908 : : }
1909 : 3 : pValue->SetValue( fSaveVal );
1910 [ + - ]: 3 : pDok->SetDirty( aVRange );
1911 [ + - ]: 3 : pFormula->Interpret();
1912 [ + + ]: 3 : if ( !bDoneIteration )
1913 : 1 : SetError(NOTAVAILABLE);
1914 [ + - ]: 3 : PushDouble(nX);
1915 : : }
1916 : : else
1917 : : {
1918 [ # # ]: 0 : if ( !bDoneIteration )
1919 : 0 : SetError(NOTAVAILABLE);
1920 [ # # ]: 0 : PushInt(0); // falsche Zelltypen
1921 : : }
1922 : : }
1923 : : else
1924 : : {
1925 [ # # ]: 0 : if ( !bDoneIteration )
1926 : 0 : SetError(NOTAVAILABLE);
1927 [ # # ]: 3 : PushInt(0); // nGlobalError
1928 : : }
1929 : : }
1930 : 3 : }
1931 : :
1932 : 0 : void ScInterpreter::ScIntersect()
1933 : : {
1934 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntersect" );
1935 [ # # ]: 0 : formula::FormulaTokenRef p2nd = PopToken();
1936 [ # # ]: 0 : formula::FormulaTokenRef p1st = PopToken();
1937 : :
1938 [ # # ][ # # ]: 0 : if (nGlobalError || !p2nd || !p1st)
[ # # ][ # # ]
1939 : : {
1940 [ # # ]: 0 : PushIllegalArgument();
1941 : : return;
1942 : : }
1943 : :
1944 : 0 : StackVar sv1 = p1st->GetType();
1945 : 0 : StackVar sv2 = p2nd->GetType();
1946 [ # # ][ # # ]: 0 : if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
[ # # ][ # # ]
[ # # ][ # # ]
1947 : : (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
1948 : : {
1949 [ # # ]: 0 : PushIllegalArgument();
1950 : : return;
1951 : : }
1952 : :
1953 : 0 : ScToken* x1 = static_cast<ScToken*>(p1st.get());
1954 : 0 : ScToken* x2 = static_cast<ScToken*>(p2nd.get());
1955 [ # # ][ # # ]: 0 : if (sv1 == svRefList || sv2 == svRefList)
1956 : : {
1957 : : // Now this is a bit nasty but it simplifies things, and having
1958 : : // intersections with lists isn't too common, if at all..
1959 : : // Convert a reference to list.
1960 : 0 : ScToken* xt[2] = { x1, x2 };
1961 : 0 : StackVar sv[2] = { sv1, sv2 };
1962 [ # # ]: 0 : for (size_t i=0; i<2; ++i)
1963 : : {
1964 [ # # ]: 0 : if (sv[i] == svSingleRef)
1965 : : {
1966 : : ScComplexRefData aRef;
1967 [ # # ]: 0 : aRef.Ref1 = aRef.Ref2 = xt[i]->GetSingleRef();
1968 [ # # ][ # # ]: 0 : xt[i] = new ScRefListToken;
1969 [ # # ][ # # ]: 0 : xt[i]->GetRefList()->push_back( aRef);
1970 : : }
1971 [ # # ]: 0 : else if (sv[i] == svDoubleRef)
1972 : : {
1973 [ # # ]: 0 : ScComplexRefData aRef = xt[i]->GetDoubleRef();
1974 [ # # ][ # # ]: 0 : xt[i] = new ScRefListToken;
1975 [ # # ][ # # ]: 0 : xt[i]->GetRefList()->push_back( aRef);
1976 : : }
1977 : : }
1978 : 0 : x1 = xt[0], x2 = xt[1];
1979 : :
1980 [ # # ]: 0 : x1->CalcAbsIfRel( aPos);
1981 [ # # ]: 0 : x2->CalcAbsIfRel( aPos);
1982 [ # # ][ # # ]: 0 : ScTokenRef xRes = new ScRefListToken;
1983 [ # # ]: 0 : ScRefList* pRefList = xRes->GetRefList();
1984 [ # # ][ # # ]: 0 : ScRefList::const_iterator end1( x1->GetRefList()->end());
1985 [ # # ][ # # ]: 0 : ScRefList::const_iterator end2( x2->GetRefList()->end());
1986 [ # # ][ # # ]: 0 : for (ScRefList::const_iterator it1( x1->GetRefList()->begin());
[ # # ][ # # ]
1987 : : it1 != end1; ++it1)
1988 : : {
1989 : 0 : const ScSingleRefData& r11 = (*it1).Ref1;
1990 : 0 : const ScSingleRefData& r12 = (*it1).Ref2;
1991 [ # # ][ # # ]: 0 : for (ScRefList::const_iterator it2( x2->GetRefList()->begin());
[ # # ][ # # ]
1992 : : it2 != end2; ++it2)
1993 : : {
1994 : 0 : const ScSingleRefData& r21 = (*it2).Ref1;
1995 : 0 : const ScSingleRefData& r22 = (*it2).Ref2;
1996 [ # # ]: 0 : SCCOL nCol1 = ::std::max( r11.nCol, r21.nCol);
1997 [ # # ]: 0 : SCROW nRow1 = ::std::max( r11.nRow, r21.nRow);
1998 [ # # ]: 0 : SCTAB nTab1 = ::std::max( r11.nTab, r21.nTab);
1999 [ # # ]: 0 : SCCOL nCol2 = ::std::min( r12.nCol, r22.nCol);
2000 [ # # ]: 0 : SCROW nRow2 = ::std::min( r12.nRow, r22.nRow);
2001 [ # # ]: 0 : SCTAB nTab2 = ::std::min( r12.nTab, r22.nTab);
2002 [ # # ][ # # ]: 0 : if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
[ # # ]
2003 : : ; // nothing
2004 : : else
2005 : : {
2006 : : ScComplexRefData aRef;
2007 : 0 : aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2008 [ # # ]: 0 : pRefList->push_back( aRef);
2009 : : }
2010 : : }
2011 : : }
2012 : 0 : size_t n = pRefList->size();
2013 [ # # ]: 0 : if (!n)
2014 [ # # ]: 0 : PushError( errNoRef);
2015 [ # # ]: 0 : else if (n == 1)
2016 : : {
2017 : 0 : const ScComplexRefData& rRef = (*pRefList)[0];
2018 [ # # ][ # # ]: 0 : if (rRef.Ref1 == rRef.Ref2)
2019 [ # # ][ # # ]: 0 : PushTempToken( new ScSingleRefToken( rRef.Ref1));
[ # # ]
2020 : : else
2021 [ # # ][ # # ]: 0 : PushTempToken( new ScDoubleRefToken( rRef));
[ # # ]
2022 : : }
2023 : : else
2024 [ # # ][ # # ]: 0 : PushTempToken( xRes.get());
2025 : : }
2026 : : else
2027 : : {
2028 : 0 : ScToken* pt[2] = { x1, x2 };
2029 : 0 : StackVar sv[2] = { sv1, sv2 };
2030 : : SCCOL nC1[2], nC2[2];
2031 : : SCROW nR1[2], nR2[2];
2032 : : SCTAB nT1[2], nT2[2];
2033 [ # # ]: 0 : for (size_t i=0; i<2; ++i)
2034 : : {
2035 [ # # ]: 0 : switch (sv[i])
2036 : : {
2037 : : case svSingleRef:
2038 : : case svDoubleRef:
2039 [ # # ]: 0 : pt[i]->CalcAbsIfRel( aPos);
2040 : : {
2041 [ # # ]: 0 : const ScSingleRefData& r = pt[i]->GetSingleRef();
2042 : 0 : nC1[i] = r.nCol;
2043 : 0 : nR1[i] = r.nRow;
2044 : 0 : nT1[i] = r.nTab;
2045 : : }
2046 [ # # ]: 0 : if (sv[i] == svDoubleRef)
2047 : : {
2048 [ # # ]: 0 : const ScSingleRefData& r = pt[i]->GetSingleRef2();
2049 : 0 : nC2[i] = r.nCol;
2050 : 0 : nR2[i] = r.nRow;
2051 : 0 : nT2[i] = r.nTab;
2052 : : }
2053 : : else
2054 : : {
2055 : 0 : nC2[i] = nC1[i];
2056 : 0 : nR2[i] = nR1[i];
2057 : 0 : nT2[i] = nT1[i];
2058 : : }
2059 : 0 : break;
2060 : : default:
2061 : : ; // nothing, prevent compiler warning
2062 : : }
2063 : : }
2064 [ # # ]: 0 : SCCOL nCol1 = ::std::max( nC1[0], nC1[1]);
2065 [ # # ]: 0 : SCROW nRow1 = ::std::max( nR1[0], nR1[1]);
2066 [ # # ]: 0 : SCTAB nTab1 = ::std::max( nT1[0], nT1[1]);
2067 [ # # ]: 0 : SCCOL nCol2 = ::std::min( nC2[0], nC2[1]);
2068 [ # # ]: 0 : SCROW nRow2 = ::std::min( nR2[0], nR2[1]);
2069 [ # # ]: 0 : SCTAB nTab2 = ::std::min( nT2[0], nT2[1]);
2070 [ # # ][ # # ]: 0 : if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
[ # # ]
2071 [ # # ]: 0 : PushError( errNoRef);
2072 [ # # ][ # # ]: 0 : else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1)
[ # # ]
2073 [ # # ]: 0 : PushSingleRef( nCol1, nRow1, nTab1);
2074 : : else
2075 [ # # ]: 0 : PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2076 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
2077 : : }
2078 : :
2079 : :
2080 : 0 : void ScInterpreter::ScRangeFunc()
2081 : : {
2082 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRangeFunc" );
2083 [ # # ]: 0 : formula::FormulaTokenRef x2 = PopToken();
2084 [ # # ]: 0 : formula::FormulaTokenRef x1 = PopToken();
2085 : :
2086 [ # # ][ # # ]: 0 : if (nGlobalError || !x2 || !x1)
[ # # ][ # # ]
2087 : : {
2088 [ # # ]: 0 : PushIllegalArgument();
2089 : 0 : return;
2090 : : }
2091 [ # # ]: 0 : FormulaTokenRef xRes = ScToken::ExtendRangeReference( *x1, *x2, aPos, false);
2092 [ # # ]: 0 : if (!xRes)
2093 [ # # ]: 0 : PushIllegalArgument();
2094 : : else
2095 [ # # ][ # # ]: 0 : PushTempToken( xRes.get());
[ # # ][ # # ]
[ # # ][ # # ]
2096 : : }
2097 : :
2098 : :
2099 : 0 : void ScInterpreter::ScUnionFunc()
2100 : : {
2101 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnionFunc" );
2102 [ # # ]: 0 : formula::FormulaTokenRef p2nd = PopToken();
2103 [ # # ]: 0 : formula::FormulaTokenRef p1st = PopToken();
2104 : :
2105 [ # # ][ # # ]: 0 : if (nGlobalError || !p2nd || !p1st)
[ # # ][ # # ]
2106 : : {
2107 [ # # ]: 0 : PushIllegalArgument();
2108 : : return;
2109 : : }
2110 : :
2111 : 0 : StackVar sv1 = p1st->GetType();
2112 : 0 : StackVar sv2 = p2nd->GetType();
2113 [ # # ][ # # ]: 0 : if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
[ # # ][ # # ]
[ # # ][ # # ]
2114 : : (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
2115 : : {
2116 [ # # ]: 0 : PushIllegalArgument();
2117 : : return;
2118 : : }
2119 : :
2120 : 0 : ScToken* x1 = static_cast<ScToken*>(p1st.get());
2121 : 0 : ScToken* x2 = static_cast<ScToken*>(p2nd.get());
2122 : :
2123 : :
2124 : 0 : ScTokenRef xRes;
2125 : : // Append to an existing RefList if there is one.
2126 [ # # ]: 0 : if (sv1 == svRefList)
2127 : : {
2128 [ # # ]: 0 : xRes = x1;
2129 : 0 : sv1 = svUnknown; // mark as handled
2130 : : }
2131 [ # # ]: 0 : else if (sv2 == svRefList)
2132 : : {
2133 [ # # ]: 0 : xRes = x2;
2134 : 0 : sv2 = svUnknown; // mark as handled
2135 : : }
2136 : : else
2137 [ # # ][ # # ]: 0 : xRes = new ScRefListToken;
[ # # ]
2138 [ # # ]: 0 : ScRefList* pRes = xRes->GetRefList();
2139 : 0 : ScToken* pt[2] = { x1, x2 };
2140 : 0 : StackVar sv[2] = { sv1, sv2 };
2141 [ # # ]: 0 : for (size_t i=0; i<2; ++i)
2142 : : {
2143 [ # # ]: 0 : if (pt[i] == xRes)
2144 : 0 : continue;
2145 [ # # # # ]: 0 : switch (sv[i])
2146 : : {
2147 : : case svSingleRef:
2148 : : {
2149 : : ScComplexRefData aRef;
2150 [ # # ]: 0 : aRef.Ref1 = aRef.Ref2 = pt[i]->GetSingleRef();
2151 [ # # ]: 0 : pRes->push_back( aRef);
2152 : : }
2153 : 0 : break;
2154 : : case svDoubleRef:
2155 [ # # ][ # # ]: 0 : pRes->push_back( pt[i]->GetDoubleRef());
2156 : 0 : break;
2157 : : case svRefList:
2158 : : {
2159 [ # # ]: 0 : const ScRefList* p = pt[i]->GetRefList();
2160 : 0 : ScRefList::const_iterator it( p->begin());
2161 : 0 : ScRefList::const_iterator end( p->end());
2162 [ # # ][ # # ]: 0 : for ( ; it != end; ++it)
2163 : : {
2164 [ # # ]: 0 : pRes->push_back( *it);
2165 : : }
2166 : : }
2167 : 0 : break;
2168 : : default:
2169 : : ; // nothing, prevent compiler warning
2170 : : }
2171 : : }
2172 [ # # ]: 0 : ValidateRef( *pRes); // set #REF! if needed
2173 [ # # ][ # # ]: 0 : PushTempToken( xRes.get());
[ # # ][ # # ]
[ # # ][ # # ]
2174 : : }
2175 : :
2176 : :
2177 : 3 : void ScInterpreter::ScCurrent()
2178 : : {
2179 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrent" );
2180 [ + - ]: 3 : FormulaTokenRef xTok( PopToken());
2181 [ + - ]: 3 : if (xTok)
2182 : : {
2183 [ + - ]: 3 : PushTempToken( xTok.get());
2184 [ + - ]: 3 : PushTempToken( xTok.get());
2185 : : }
2186 : : else
2187 [ # # ][ + - ]: 3 : PushError( errUnknownStackVariable);
2188 : 3 : }
2189 : :
2190 : 0 : void ScInterpreter::ScStyle()
2191 : : {
2192 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStyle" );
2193 : 0 : sal_uInt8 nParamCount = GetByte();
2194 [ # # ][ # # ]: 0 : if (nParamCount >= 1 && nParamCount <= 3)
2195 : : {
2196 [ # # ]: 0 : String aStyle2; // Vorlage nach Timer
2197 [ # # ]: 0 : if (nParamCount >= 3)
2198 [ # # ][ # # ]: 0 : aStyle2 = GetString();
2199 : 0 : long nTimeOut = 0; // Timeout
2200 [ # # ]: 0 : if (nParamCount >= 2)
2201 [ # # ]: 0 : nTimeOut = (long)(GetDouble()*1000.0);
2202 [ # # ][ # # ]: 0 : String aStyle1 = GetString(); // Vorlage fuer sofort
2203 : :
2204 [ # # ]: 0 : if (nTimeOut < 0)
2205 : 0 : nTimeOut = 0;
2206 : :
2207 : : //
2208 : : // Request ausfuehren, um Vorlage anzuwenden
2209 : : //
2210 : :
2211 [ # # ]: 0 : if ( !pDok->IsClipOrUndo() )
2212 : : {
2213 : 0 : SfxObjectShell* pShell = pDok->GetDocumentShell();
2214 [ # # ]: 0 : if (pShell)
2215 : : {
2216 : : //! notify object shell directly
2217 : :
2218 : 0 : ScRange aRange(aPos);
2219 [ # # ]: 0 : ScAutoStyleHint aHint( aRange, aStyle1, nTimeOut, aStyle2 );
2220 [ # # ][ # # ]: 0 : pShell->Broadcast( aHint );
2221 : : }
2222 : : }
2223 : :
2224 [ # # ][ # # ]: 0 : PushDouble(0.0);
[ # # ]
2225 : : }
2226 : : else
2227 : 0 : PushIllegalParameter();
2228 : 0 : }
2229 : :
2230 : 8 : ScDdeLink* lcl_GetDdeLink( sfx2::LinkManager* pLinkMgr,
2231 : : const String& rA, const String& rT, const String& rI, sal_uInt8 nM )
2232 : : {
2233 : 8 : sal_uInt16 nCount = pLinkMgr->GetLinks().size();
2234 [ + + ]: 8 : for (sal_uInt16 i=0; i<nCount; i++ )
2235 : : {
2236 : 5 : ::sfx2::SvBaseLink* pBase = *pLinkMgr->GetLinks()[i];
2237 [ + - ]: 5 : if (pBase->ISA(ScDdeLink))
2238 : : {
2239 : 5 : ScDdeLink* pLink = (ScDdeLink*)pBase;
2240 [ + - + - : 20 : if ( pLink->GetAppl() == rA &&
+ - + - ]
[ + - ]
2241 : 5 : pLink->GetTopic() == rT &&
2242 : 5 : pLink->GetItem() == rI &&
2243 : 5 : pLink->GetMode() == nM )
2244 : 5 : return pLink;
2245 : : }
2246 : : }
2247 : :
2248 : 8 : return NULL;
2249 : : }
2250 : :
2251 : 8 : void ScInterpreter::ScDde()
2252 : : {
2253 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDde" );
2254 : : // Applikation, Datei, Bereich
2255 : : // Application, Topic, Item
2256 : :
2257 : 8 : sal_uInt8 nParamCount = GetByte();
2258 [ + - ]: 8 : if ( MustHaveParamCount( nParamCount, 3, 4 ) )
2259 : : {
2260 : 8 : sal_uInt8 nMode = SC_DDE_DEFAULT;
2261 [ - + ]: 8 : if (nParamCount == 4)
2262 [ # # ]: 0 : nMode = (sal_uInt8) ::rtl::math::approxFloor(GetDouble());
2263 [ + - ][ + - ]: 8 : String aItem = GetString();
2264 [ + - ][ + - ]: 8 : String aTopic = GetString();
2265 [ + - ][ + - ]: 8 : String aAppl = GetString();
2266 : :
2267 [ - + ]: 8 : if (nMode > SC_DDE_TEXT)
2268 : 0 : nMode = SC_DDE_DEFAULT;
2269 : :
2270 : : // temporary documents (ScFunctionAccess) have no DocShell
2271 : : // and no LinkManager -> abort
2272 : :
2273 [ + - ]: 8 : sfx2::LinkManager* pLinkMgr = pDok->GetLinkManager();
2274 [ - + ]: 8 : if (!pLinkMgr)
2275 : : {
2276 [ # # ]: 0 : PushNoValue();
2277 : 8 : return;
2278 : : }
2279 : :
2280 : : // Nach dem Laden muss neu interpretiert werden (Verknuepfungen aufbauen)
2281 : :
2282 [ + - ]: 8 : if ( pMyFormulaCell->GetCode()->IsRecalcModeNormal() )
2283 : 8 : pMyFormulaCell->GetCode()->SetRecalcModeOnLoad();
2284 : :
2285 : : // solange der Link nicht ausgewertet ist, Idle abklemmen
2286 : : // (um zirkulaere Referenzen zu vermeiden)
2287 : :
2288 : 8 : bool bOldDis = pDok->IsIdleDisabled();
2289 : 8 : pDok->DisableIdle( true );
2290 : :
2291 : : // Link-Objekt holen / anlegen
2292 : :
2293 [ + - ]: 8 : ScDdeLink* pLink = lcl_GetDdeLink( pLinkMgr, aAppl, aTopic, aItem, nMode );
2294 : :
2295 : : //! Dde-Links (zusaetzlich) effizienter am Dokument speichern !!!!!
2296 : : // ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem );
2297 : :
2298 [ + - ]: 8 : bool bWasError = ( pMyFormulaCell->GetRawError() != 0 );
2299 : :
2300 [ + + ]: 8 : if (!pLink)
2301 : : {
2302 [ + - ][ + - ]: 3 : pLink = new ScDdeLink( pDok, aAppl, aTopic, aItem, nMode );
2303 [ + - ]: 3 : pLinkMgr->InsertDDELink( pLink, aAppl, aTopic, aItem );
2304 [ + - ]: 3 : if ( pLinkMgr->GetLinks().size() == 1 ) // erster ?
2305 : : {
2306 [ + - ]: 3 : SfxBindings* pBindings = pDok->GetViewBindings();
2307 [ + - ]: 3 : if (pBindings)
2308 [ + - ]: 3 : pBindings->Invalidate( SID_LINKS ); // Link-Manager enablen
2309 : : }
2310 : :
2311 : : //! asynchron auswerten ???
2312 [ + - ]: 3 : pLink->TryUpdate(); // TryUpdate ruft Update nicht mehrfach auf
2313 : :
2314 : : // StartListening erst nach dem Update, sonst circular reference
2315 [ + - ]: 3 : pMyFormulaCell->StartListening( *pLink );
2316 : : }
2317 : : else
2318 : : {
2319 [ + - ]: 5 : pMyFormulaCell->StartListening( *pLink );
2320 : : }
2321 : :
2322 : : // Wenn aus dem Reschedule beim Ausfuehren des Links ein Fehler
2323 : : // (z.B. zirkulaere Referenz) entstanden ist, der vorher nicht da war,
2324 : : // das Fehler-Flag zuruecksetzen:
2325 : :
2326 [ + - ][ - + ]: 8 : if ( pMyFormulaCell->GetRawError() && !bWasError )
[ # # ][ - + ]
2327 [ # # ]: 0 : pMyFormulaCell->SetErrCode(0);
2328 : :
2329 : : // Wert abfragen
2330 : :
2331 [ + - ]: 8 : const ScMatrix* pLinkMat = pLink->GetResult();
2332 [ + - ]: 8 : if (pLinkMat)
2333 : : {
2334 : : SCSIZE nC, nR;
2335 [ + - ]: 8 : pLinkMat->GetDimensions(nC, nR);
2336 [ + - ]: 8 : ScMatrixRef pNewMat = GetNewMat( nC, nR);
2337 [ + - ]: 8 : if (pNewMat)
2338 : : {
2339 [ + - ]: 8 : pLinkMat->MatCopy(*pNewMat); // kopieren
2340 [ + - ]: 8 : PushMatrix( pNewMat );
2341 : : }
2342 : : else
2343 [ # # ][ + - ]: 8 : PushIllegalArgument();
2344 : : }
2345 : : else
2346 [ # # ]: 0 : PushNA();
2347 : :
2348 : 8 : pDok->DisableIdle( bOldDis );
2349 [ + - ][ - + ]: 8 : pLinkMgr->CloseCachedComps();
[ + - ][ - + ]
[ + - ][ + - ]
[ + - ]
2350 : : }
2351 : : }
2352 : :
2353 : 0 : void ScInterpreter::ScBase()
2354 : : { // Value, Base [, MinLen]
2355 : 0 : sal_uInt8 nParamCount = GetByte();
2356 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
2357 : : {
2358 : : static const sal_Unicode pDigits[] = {
2359 : : '0','1','2','3','4','5','6','7','8','9',
2360 : : 'A','B','C','D','E','F','G','H','I','J','K','L','M',
2361 : : 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2362 : : 0
2363 : : };
2364 : : static const int nDigits = (sizeof (pDigits)/sizeof(pDigits[0]))-1;
2365 : : xub_StrLen nMinLen;
2366 [ # # ]: 0 : if ( nParamCount == 3 )
2367 : : {
2368 : 0 : double fLen = ::rtl::math::approxFloor( GetDouble() );
2369 [ # # ][ # # ]: 0 : if ( 1.0 <= fLen && fLen < STRING_MAXLEN )
2370 : 0 : nMinLen = (xub_StrLen) fLen;
2371 [ # # ]: 0 : else if ( fLen == 0.0 )
2372 : 0 : nMinLen = 1;
2373 : : else
2374 : 0 : nMinLen = 0; // Error
2375 : : }
2376 : : else
2377 : 0 : nMinLen = 1;
2378 : 0 : double fBase = ::rtl::math::approxFloor( GetDouble() );
2379 : 0 : double fVal = ::rtl::math::approxFloor( GetDouble() );
2380 : : double fChars = ((fVal > 0.0 && fBase > 0.0) ?
2381 : 0 : (ceil( log( fVal ) / log( fBase ) ) + 2.0) :
2382 [ # # ][ # # ]: 0 : 2.0);
2383 [ # # ]: 0 : if ( fChars >= STRING_MAXLEN )
2384 : 0 : nMinLen = 0; // Error
2385 : :
2386 [ # # ][ # # ]: 0 : if ( !nGlobalError && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal )
[ # # ][ # # ]
[ # # ]
2387 : : {
2388 : 0 : const xub_StrLen nConstBuf = 128;
2389 : : sal_Unicode aBuf[nConstBuf];
2390 : 0 : xub_StrLen nBuf = Max( (xub_StrLen) fChars, (xub_StrLen) (nMinLen+1) );
2391 [ # # ][ # # ]: 0 : sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]);
2392 [ # # ]: 0 : for ( xub_StrLen j = 0; j < nBuf; ++j )
2393 : : {
2394 : 0 : pBuf[j] = '0';
2395 : : }
2396 : 0 : sal_Unicode* p = pBuf + nBuf - 1;
2397 : 0 : *p = 0;
2398 [ # # ]: 0 : if ( fVal <= (sal_uLong)(~0) )
2399 : : {
2400 : 0 : sal_uLong nVal = (sal_uLong) fVal;
2401 : 0 : sal_uLong nBase = (sal_uLong) fBase;
2402 [ # # ][ # # ]: 0 : while ( nVal && p > pBuf )
[ # # ]
2403 : : {
2404 : 0 : *--p = pDigits[ nVal % nBase ];
2405 : 0 : nVal /= nBase;
2406 : : }
2407 : 0 : fVal = (double) nVal;
2408 : : }
2409 : : else
2410 : : {
2411 : 0 : bool bDirt = false;
2412 [ # # ][ # # ]: 0 : while ( fVal && p > pBuf )
[ # # ]
2413 : : {
2414 : : //! mit fmod Rundungsfehler ab 2**48
2415 : : // double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2416 : : // so ist es etwas besser
2417 : 0 : double fInt = ::rtl::math::approxFloor( fVal / fBase );
2418 : 0 : double fMult = fInt * fBase;
2419 : : #if OSL_DEBUG_LEVEL > 1
2420 : : // =BASIS(1e308;36) => GPF mit
2421 : : // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2422 : : // trotz vorheriger Pruefung ob fVal >= fMult
2423 : : double fDebug1 = fVal - fMult;
2424 : : // fVal := 7,5975311883090e+290
2425 : : // fMult := 7,5975311883090e+290
2426 : : // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2427 : : // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2428 : : double fDebug2 = ::rtl::math::approxSub( fVal, fMult );
2429 : : // und ::rtl::math::approxSub( fVal, fMult ) == 0
2430 : : double fDebug3 = ( fInt ? fVal / fInt : 0.0 );
2431 : : // Nach dem strange fDebug1 und fVal < fMult ist eigentlich
2432 : : // fDebug2 == fBase, trotzdem wird das mit einem Vergleich
2433 : : // nicht erkannt, dann schlaegt bDirt zu und alles wird wieder gut..
2434 : :
2435 : : // prevent compiler warnings
2436 : : (void)fDebug1; (void)fDebug2; (void)fDebug3;
2437 : : #endif
2438 : : size_t nDig;
2439 [ # # ]: 0 : if ( fVal < fMult )
2440 : : { // da ist was gekippt
2441 : 0 : bDirt = true;
2442 : 0 : nDig = 0;
2443 : : }
2444 : : else
2445 : : {
2446 : 0 : double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
2447 [ # # ]: 0 : if ( bDirt )
2448 : : {
2449 : 0 : bDirt = false;
2450 : 0 : --fDig;
2451 : : }
2452 [ # # ]: 0 : if ( fDig <= 0.0 )
2453 : 0 : nDig = 0;
2454 [ # # ]: 0 : else if ( fDig >= fBase )
2455 : 0 : nDig = ((size_t) fBase) - 1;
2456 : : else
2457 : 0 : nDig = (size_t) fDig;
2458 : : }
2459 : 0 : *--p = pDigits[ nDig ];
2460 : 0 : fVal = fInt;
2461 : : }
2462 : : }
2463 [ # # ]: 0 : if ( fVal )
2464 [ # # ]: 0 : PushError( errStringOverflow );
2465 : : else
2466 : : {
2467 [ # # ]: 0 : if ( nBuf - (p - pBuf) <= nMinLen )
2468 : 0 : p = pBuf + nBuf - 1 - nMinLen;
2469 [ # # ]: 0 : PushStringBuffer( p );
2470 : : }
2471 [ # # ]: 0 : if ( pBuf != aBuf )
2472 [ # # ]: 0 : delete [] pBuf;
2473 : : }
2474 : : else
2475 : 0 : PushIllegalArgument();
2476 : : }
2477 : 0 : }
2478 : :
2479 : :
2480 : 0 : void ScInterpreter::ScDecimal()
2481 : : { // Text, Base
2482 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
2483 : : {
2484 [ # # ]: 0 : double fBase = ::rtl::math::approxFloor( GetDouble() );
2485 [ # # ][ # # ]: 0 : String aStr( GetString() );
2486 [ # # ][ # # ]: 0 : if ( !nGlobalError && 2 <= fBase && fBase <= 36 )
[ # # ]
2487 : : {
2488 : 0 : double fVal = 0.0;
2489 : 0 : int nBase = (int) fBase;
2490 : 0 : register const sal_Unicode* p = aStr.GetBuffer();
2491 [ # # ][ # # ]: 0 : while ( *p == ' ' || *p == '\t' )
[ # # ]
2492 : 0 : p++; // strip leading white space
2493 [ # # ]: 0 : if ( nBase == 16 )
2494 : : { // evtl. hex-prefix strippen
2495 [ # # ][ # # ]: 0 : if ( *p == 'x' || *p == 'X' )
2496 : 0 : p++;
2497 [ # # ][ # # ]: 0 : else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') )
[ # # ]
2498 : 0 : p += 2;
2499 : : }
2500 [ # # ]: 0 : while ( *p )
2501 : : {
2502 : : int n;
2503 [ # # ][ # # ]: 0 : if ( '0' <= *p && *p <= '9' )
2504 : 0 : n = *p - '0';
2505 [ # # ][ # # ]: 0 : else if ( 'A' <= *p && *p <= 'Z' )
2506 : 0 : n = 10 + (*p - 'A');
2507 [ # # ][ # # ]: 0 : else if ( 'a' <= *p && *p <= 'z' )
2508 : 0 : n = 10 + (*p - 'a');
2509 : : else
2510 : 0 : n = nBase;
2511 [ # # ]: 0 : if ( nBase <= n )
2512 : : {
2513 [ # # ][ # # ]: 0 : if ( *(p+1) == 0 &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
2514 : : ( (nBase == 2 && (*p == 'b' || *p == 'B'))
2515 : : ||(nBase == 16 && (*p == 'h' || *p == 'H')) )
2516 : : )
2517 : : ; // 101b und F00Dh sind ok
2518 : : else
2519 : : {
2520 [ # # ]: 0 : PushIllegalArgument();
2521 : 0 : return ;
2522 : : }
2523 : : }
2524 : : else
2525 : 0 : fVal = fVal * fBase + n;
2526 : 0 : p++;
2527 : :
2528 : : }
2529 [ # # ]: 0 : PushDouble( fVal );
2530 : : }
2531 : : else
2532 [ # # ][ # # ]: 0 : PushIllegalArgument();
[ # # ]
2533 : : }
2534 : : }
2535 : :
2536 : :
2537 : 0 : void ScInterpreter::ScConvert()
2538 : : { // Value, FromUnit, ToUnit
2539 [ # # ]: 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
2540 : : {
2541 [ # # ][ # # ]: 0 : String aToUnit( GetString() );
2542 [ # # ][ # # ]: 0 : String aFromUnit( GetString() );
2543 [ # # ]: 0 : double fVal = GetDouble();
2544 [ # # ]: 0 : if ( nGlobalError )
2545 [ # # ]: 0 : PushError( nGlobalError);
2546 : : else
2547 : : { // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert
2548 : : double fConv;
2549 [ # # ][ # # ]: 0 : if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) )
[ # # ][ # # ]
[ # # ]
2550 [ # # ]: 0 : PushDouble( fVal * fConv );
2551 [ # # ][ # # ]: 0 : else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) )
[ # # ][ # # ]
[ # # ]
2552 [ # # ]: 0 : PushDouble( fVal / fConv );
2553 : : else
2554 [ # # ]: 0 : PushNA();
2555 [ # # ][ # # ]: 0 : }
2556 : : }
2557 : 0 : }
2558 : :
2559 : :
2560 : 0 : void ScInterpreter::ScRoman()
2561 : : { // Value [Mode]
2562 : 0 : sal_uInt8 nParamCount = GetByte();
2563 [ # # ]: 0 : if( MustHaveParamCount( nParamCount, 1, 2 ) )
2564 : : {
2565 [ # # ]: 0 : double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
2566 : 0 : double fVal = ::rtl::math::approxFloor( GetDouble() );
2567 [ # # ]: 0 : if( nGlobalError )
2568 : 0 : PushError( nGlobalError);
2569 [ # # ][ # # ]: 0 : else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) )
[ # # ][ # # ]
2570 : : {
2571 : : static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2572 : : static const sal_uInt16 pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
2573 : : static const sal_uInt16 nMaxIndex = (sal_uInt16)((sizeof(pValues)/sizeof(pValues[0])) - 1);
2574 : :
2575 [ # # ]: 0 : String aRoman;
2576 : 0 : sal_uInt16 nVal = (sal_uInt16) fVal;
2577 : 0 : sal_uInt16 nMode = (sal_uInt16) fMode;
2578 : :
2579 [ # # ]: 0 : for( sal_uInt16 i = 0; i <= nMaxIndex / 2; i++ )
2580 : : {
2581 : 0 : sal_uInt16 nIndex = 2 * i;
2582 : 0 : sal_uInt16 nDigit = nVal / pValues[ nIndex ];
2583 : :
2584 [ # # ]: 0 : if( (nDigit % 5) == 4 )
2585 : : {
2586 [ # # ]: 0 : sal_uInt16 nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
2587 : 0 : sal_uInt16 nSteps = 0;
2588 [ # # ][ # # ]: 0 : while( (nSteps < nMode) && (nIndex < nMaxIndex) )
[ # # ]
2589 : : {
2590 : 0 : nSteps++;
2591 [ # # ]: 0 : if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
2592 : 0 : nIndex++;
2593 : : else
2594 : 0 : nSteps = nMode;
2595 : : }
2596 [ # # ]: 0 : aRoman += pChars[ nIndex ];
2597 [ # # ]: 0 : aRoman += pChars[ nIndex2 ];
2598 : 0 : nVal = sal::static_int_cast<sal_uInt16>( nVal + pValues[ nIndex ] );
2599 : 0 : nVal = sal::static_int_cast<sal_uInt16>( nVal - pValues[ nIndex2 ] );
2600 : : }
2601 : : else
2602 : : {
2603 [ # # ]: 0 : if( nDigit > 4 )
2604 [ # # ]: 0 : aRoman += pChars[ nIndex - 1 ];
2605 [ # # ]: 0 : aRoman.Expand( aRoman.Len() + (nDigit % 5), pChars[ nIndex ] );
2606 : 0 : nVal %= pValues[ nIndex ];
2607 : : }
2608 : : }
2609 : :
2610 [ # # ][ # # ]: 0 : PushString( aRoman );
2611 : : }
2612 : : else
2613 : 0 : PushIllegalArgument();
2614 : : }
2615 : 0 : }
2616 : :
2617 : :
2618 : 0 : bool lcl_GetArabicValue( sal_Unicode cChar, sal_uInt16& rnValue, bool& rbIsDec )
2619 : : {
2620 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBase" );
2621 [ # # # # : 0 : switch( cChar )
# # # # ]
2622 : : {
2623 : 0 : case 'M': rnValue = 1000; rbIsDec = true; break;
2624 : 0 : case 'D': rnValue = 500; rbIsDec = false; break;
2625 : 0 : case 'C': rnValue = 100; rbIsDec = true; break;
2626 : 0 : case 'L': rnValue = 50; rbIsDec = false; break;
2627 : 0 : case 'X': rnValue = 10; rbIsDec = true; break;
2628 : 0 : case 'V': rnValue = 5; rbIsDec = false; break;
2629 : 0 : case 'I': rnValue = 1; rbIsDec = true; break;
2630 : 0 : default: return false;
2631 : : }
2632 : 0 : return true;
2633 : : }
2634 : :
2635 : :
2636 : 0 : void ScInterpreter::ScArabic()
2637 : : {
2638 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArabic" );
2639 [ # # ][ # # ]: 0 : String aRoman( GetString() );
2640 [ # # ]: 0 : if( nGlobalError )
2641 [ # # ]: 0 : PushError( nGlobalError);
2642 : : else
2643 : : {
2644 [ # # ]: 0 : aRoman.ToUpperAscii();
2645 : :
2646 : 0 : sal_uInt16 nValue = 0;
2647 : 0 : sal_uInt16 nValidRest = 3999;
2648 : 0 : sal_uInt16 nCharIndex = 0;
2649 : 0 : sal_uInt16 nCharCount = aRoman.Len();
2650 : 0 : bool bValid = true;
2651 : :
2652 [ # # ][ # # ]: 0 : while( bValid && (nCharIndex < nCharCount) )
[ # # ]
2653 : : {
2654 : 0 : sal_uInt16 nDigit1 = 0;
2655 : 0 : sal_uInt16 nDigit2 = 0;
2656 : 0 : bool bIsDec1 = false;
2657 : 0 : bool bIsDec2 = false;
2658 : 0 : bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex ), nDigit1, bIsDec1 );
2659 [ # # ][ # # ]: 0 : if( bValid && (nCharIndex + 1 < nCharCount) )
2660 : 0 : bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex + 1 ), nDigit2, bIsDec2 );
2661 [ # # ]: 0 : if( bValid )
2662 : : {
2663 [ # # ]: 0 : if( nDigit1 >= nDigit2 )
2664 : : {
2665 : 0 : nValue = sal::static_int_cast<sal_uInt16>( nValue + nDigit1 );
2666 [ # # ]: 0 : nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
2667 : 0 : bValid = (nValidRest >= nDigit1);
2668 [ # # ]: 0 : if( bValid )
2669 : 0 : nValidRest = sal::static_int_cast<sal_uInt16>( nValidRest - nDigit1 );
2670 : 0 : nCharIndex++;
2671 : : }
2672 [ # # ]: 0 : else if( nDigit1 * 2 != nDigit2 )
2673 : : {
2674 : 0 : sal_uInt16 nDiff = nDigit2 - nDigit1;
2675 : 0 : nValue = sal::static_int_cast<sal_uInt16>( nValue + nDiff );
2676 : 0 : bValid = (nValidRest >= nDiff);
2677 [ # # ]: 0 : if( bValid )
2678 : 0 : nValidRest = nDigit1 - 1;
2679 : 0 : nCharIndex += 2;
2680 : : }
2681 : : else
2682 : 0 : bValid = false;
2683 : : }
2684 : : }
2685 [ # # ]: 0 : if( bValid )
2686 [ # # ]: 0 : PushInt( nValue );
2687 : : else
2688 [ # # ]: 0 : PushIllegalArgument();
2689 [ # # ]: 0 : }
2690 : 0 : }
2691 : :
2692 : :
2693 : 0 : void ScInterpreter::ScHyperLink()
2694 : : {
2695 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHyperLink" );
2696 : 0 : sal_uInt8 nParamCount = GetByte();
2697 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
2698 : : {
2699 : 0 : double fVal = 0.0;
2700 [ # # ]: 0 : String aStr;
2701 : 0 : ScMatValType nResultType = SC_MATVAL_STRING;
2702 : :
2703 [ # # ]: 0 : if ( nParamCount == 2 )
2704 : : {
2705 [ # # ][ # # : 0 : switch ( GetStackType() )
# # # # ]
2706 : : {
2707 : : case svDouble:
2708 [ # # ]: 0 : fVal = GetDouble();
2709 : 0 : nResultType = SC_MATVAL_VALUE;
2710 : 0 : break;
2711 : : case svString:
2712 [ # # ][ # # ]: 0 : aStr = GetString();
2713 : 0 : break;
2714 : : case svSingleRef:
2715 : : case svDoubleRef:
2716 : : {
2717 : 0 : ScAddress aAdr;
2718 [ # # ][ # # ]: 0 : if ( !PopDoubleRefOrSingleRef( aAdr ) )
2719 : : break;
2720 [ # # ]: 0 : ScBaseCell* pCell = GetCell( aAdr );
2721 [ # # ][ # # ]: 0 : if (HasCellEmptyData( pCell))
2722 : 0 : nResultType = SC_MATVAL_EMPTY;
2723 : : else
2724 : : {
2725 [ # # ]: 0 : sal_uInt16 nErr = GetCellErrCode( pCell );
2726 [ # # ]: 0 : if (nErr)
2727 : 0 : SetError( nErr);
2728 [ # # ][ # # ]: 0 : else if (HasCellValueData( pCell))
2729 : : {
2730 [ # # ]: 0 : fVal = GetCellValue( aAdr, pCell );
2731 : 0 : nResultType = SC_MATVAL_VALUE;
2732 : : }
2733 : : else
2734 [ # # ]: 0 : GetCellString( aStr, pCell );
2735 : : }
2736 : : }
2737 : 0 : break;
2738 : : case svMatrix:
2739 [ # # ]: 0 : nResultType = GetDoubleOrStringFromMatrix( fVal, aStr);
2740 : 0 : break;
2741 : : case svMissing:
2742 : : case svEmptyCell:
2743 [ # # ]: 0 : Pop();
2744 : : // mimic xcl
2745 : 0 : fVal = 0.0;
2746 : 0 : nResultType = SC_MATVAL_VALUE;
2747 : 0 : break;
2748 : : default:
2749 [ # # ]: 0 : PopError();
2750 : 0 : SetError( errIllegalArgument);
2751 : : }
2752 : : }
2753 [ # # ][ # # ]: 0 : String aUrl = GetString();
2754 [ # # ]: 0 : ScMatrixRef pResMat = GetNewMat( 1, 2);
2755 [ # # ]: 0 : if (nGlobalError)
2756 : : {
2757 : 0 : fVal = CreateDoubleError( nGlobalError);
2758 : 0 : nResultType = SC_MATVAL_VALUE;
2759 : : }
2760 [ # # ][ # # ]: 0 : if (nParamCount == 2 || nGlobalError)
2761 : : {
2762 [ # # ]: 0 : if (ScMatrix::IsValueType( nResultType))
2763 [ # # ]: 0 : pResMat->PutDouble( fVal, 0);
2764 [ # # ]: 0 : else if (ScMatrix::IsRealStringType( nResultType))
2765 [ # # ][ # # ]: 0 : pResMat->PutString( aStr, 0);
2766 : : else // EmptyType, EmptyPathType, mimic xcl
2767 [ # # ]: 0 : pResMat->PutDouble( 0.0, 0 );
2768 : : }
2769 : : else
2770 [ # # ][ # # ]: 0 : pResMat->PutString( aUrl, 0 );
2771 [ # # ][ # # ]: 0 : pResMat->PutString( aUrl, 1 );
2772 : 0 : bMatrixFormula = true;
2773 [ # # ][ # # ]: 0 : PushMatrix(pResMat);
[ # # ][ # # ]
2774 : : }
2775 : 0 : }
2776 : :
2777 : :
2778 : 0 : bool lclConvertMoney( const String& aSearchUnit, double& rfRate, int& rnDec )
2779 : : {
2780 : : struct ConvertInfo
2781 : : {
2782 : : const sal_Char* pCurrText;
2783 : : double fRate;
2784 : : int nDec;
2785 : : };
2786 : : ConvertInfo aConvertTable[] = {
2787 : : { "EUR", 1.0, 2 },
2788 : : { "ATS", 13.7603, 2 },
2789 : : { "BEF", 40.3399, 0 },
2790 : : { "DEM", 1.95583, 2 },
2791 : : { "ESP", 166.386, 0 },
2792 : : { "FIM", 5.94573, 2 },
2793 : : { "FRF", 6.55957, 2 },
2794 : : { "IEP", 0.787564, 2 },
2795 : : { "ITL", 1936.27, 0 },
2796 : : { "LUF", 40.3399, 0 },
2797 : : { "NLG", 2.20371, 2 },
2798 : : { "PTE", 200.482, 2 },
2799 : : { "GRD", 340.750, 2 },
2800 : : { "SIT", 239.640, 2 },
2801 : : { "MTL", 0.429300, 2 },
2802 : : { "CYP", 0.585274, 2 },
2803 : : { "SKK", 30.1260, 2 }
2804 : 0 : };
2805 : :
2806 : 0 : const size_t nConversionCount = sizeof( aConvertTable ) / sizeof( aConvertTable[0] );
2807 [ # # ]: 0 : for ( size_t i = 0; i < nConversionCount; i++ )
2808 [ # # ][ # # ]: 0 : if ( aSearchUnit.EqualsIgnoreCaseAscii( aConvertTable[i].pCurrText ) )
2809 : : {
2810 : 0 : rfRate = aConvertTable[i].fRate;
2811 : 0 : rnDec = aConvertTable[i].nDec;
2812 : 0 : return true;
2813 : : }
2814 : 0 : return false;
2815 : : }
2816 : :
2817 : 0 : void ScInterpreter::ScEuroConvert()
2818 : : { //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
2819 : 0 : sal_uInt8 nParamCount = GetByte();
2820 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 3, 5 ) )
2821 : : {
2822 : 0 : double nPrecision = 0.0;
2823 [ # # ]: 0 : if ( nParamCount == 5 )
2824 : : {
2825 [ # # ]: 0 : nPrecision = ::rtl::math::approxFloor(GetDouble());
2826 [ # # ]: 0 : if ( nPrecision < 3 )
2827 : : {
2828 [ # # ]: 0 : PushIllegalArgument();
2829 : 0 : return;
2830 : : }
2831 : : }
2832 : 0 : bool bFullPrecision = false;
2833 [ # # ]: 0 : if ( nParamCount >= 4 )
2834 [ # # ]: 0 : bFullPrecision = GetBool();
2835 [ # # ][ # # ]: 0 : String aToUnit( GetString() );
2836 [ # # ][ # # ]: 0 : String aFromUnit( GetString() );
2837 [ # # ]: 0 : double fVal = GetDouble();
2838 [ # # ]: 0 : if ( nGlobalError )
2839 [ # # ]: 0 : PushError( nGlobalError);
2840 : : else
2841 : : {
2842 : : double fFromRate;
2843 : : double fToRate;
2844 : : int nFromDec;
2845 : : int nToDec;
2846 [ # # ]: 0 : String aEur( RTL_CONSTASCII_USTRINGPARAM("EUR"));
2847 [ # # ][ # # ]: 0 : if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec )
[ # # ][ # # ]
2848 [ # # ]: 0 : && lclConvertMoney( aToUnit, fToRate, nToDec ) )
2849 : : {
2850 : : double fRes;
2851 [ # # ][ # # ]: 0 : if ( aFromUnit.EqualsIgnoreCaseAscii( aToUnit ) )
2852 : 0 : fRes = fVal;
2853 : : else
2854 : : {
2855 [ # # ][ # # ]: 0 : if ( aFromUnit.EqualsIgnoreCaseAscii( aEur ) )
2856 : 0 : fRes = fVal * fToRate;
2857 : : else
2858 : : {
2859 : 0 : double fIntermediate = fVal / fFromRate;
2860 [ # # ]: 0 : if ( nPrecision )
2861 : : fIntermediate = ::rtl::math::round( fIntermediate,
2862 : 0 : (int) nPrecision );
2863 : 0 : fRes = fIntermediate * fToRate;
2864 : : }
2865 [ # # ]: 0 : if ( !bFullPrecision )
2866 : 0 : fRes = ::rtl::math::round( fRes, nToDec );
2867 : : }
2868 [ # # ]: 0 : PushDouble( fRes );
2869 : : }
2870 : : else
2871 [ # # ][ # # ]: 0 : PushIllegalArgument();
2872 [ # # ][ # # ]: 0 : }
2873 : : }
2874 : : }
2875 : :
2876 : :
2877 : : // BAHTTEXT ===================================================================
2878 : :
2879 : : #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
2880 : : #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
2881 : : #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
2882 : : #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
2883 : : #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
2884 : : #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
2885 : : #define UTF8_TH_6 "\340\270\253\340\270\201"
2886 : : #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
2887 : : #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
2888 : : #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
2889 : : #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
2890 : : #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
2891 : : #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
2892 : : #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
2893 : : #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
2894 : : #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
2895 : : #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
2896 : : #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
2897 : : #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
2898 : : #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
2899 : : #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
2900 : : #define UTF8_TH_MINUS "\340\270\245\340\270\232"
2901 : :
2902 : : // local functions ------------------------------------------------------------
2903 : :
2904 : : namespace {
2905 : :
2906 : 0 : inline void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize )
2907 : : {
2908 : 0 : rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 );
2909 : 0 : }
2910 : :
2911 : : /** Appends a digit (0 to 9) to the passed string. */
2912 : 0 : void lclAppendDigit( rtl::OStringBuffer& rText, sal_Int32 nDigit )
2913 : : {
2914 [ # # # # : 0 : switch( nDigit )
# # # # #
# # ]
2915 : : {
2916 : 0 : case 0: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_0) ); break;
2917 : 0 : case 1: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_1) ); break;
2918 : 0 : case 2: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_2) ); break;
2919 : 0 : case 3: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_3) ); break;
2920 : 0 : case 4: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_4) ); break;
2921 : 0 : case 5: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_5) ); break;
2922 : 0 : case 6: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_6) ); break;
2923 : 0 : case 7: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_7) ); break;
2924 : 0 : case 8: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_8) ); break;
2925 : 0 : case 9: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_9) ); break;
2926 : : default: OSL_FAIL( "lclAppendDigit - illegal digit" );
2927 : : }
2928 : 0 : }
2929 : :
2930 : : /** Appends a value raised to a power of 10: nDigit*10^nPow10.
2931 : : @param nDigit A digit in the range from 1 to 9.
2932 : : @param nPow10 A value in the range from 2 to 5.
2933 : : */
2934 : 0 : void lclAppendPow10( rtl::OStringBuffer& rText, sal_Int32 nDigit, sal_Int32 nPow10 )
2935 : : {
2936 : : OSL_ENSURE( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" );
2937 : 0 : lclAppendDigit( rText, nDigit );
2938 [ # # # # : 0 : switch( nPow10 )
# ]
2939 : : {
2940 : 0 : case 2: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_1E2) ); break;
2941 : 0 : case 3: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_1E3) ); break;
2942 : 0 : case 4: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_1E4) ); break;
2943 : 0 : case 5: rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_1E5) ); break;
2944 : : default: OSL_FAIL( "lclAppendPow10 - illegal power" );
2945 : : }
2946 : 0 : }
2947 : :
2948 : : /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
2949 : 0 : void lclAppendBlock( rtl::OStringBuffer& rText, sal_Int32 nValue )
2950 : : {
2951 : : OSL_ENSURE( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" );
2952 [ # # ]: 0 : if( nValue >= 100000 )
2953 : : {
2954 : 0 : lclAppendPow10( rText, nValue / 100000, 5 );
2955 : 0 : nValue %= 100000;
2956 : : }
2957 [ # # ]: 0 : if( nValue >= 10000 )
2958 : : {
2959 : 0 : lclAppendPow10( rText, nValue / 10000, 4 );
2960 : 0 : nValue %= 10000;
2961 : : }
2962 [ # # ]: 0 : if( nValue >= 1000 )
2963 : : {
2964 : 0 : lclAppendPow10( rText, nValue / 1000, 3 );
2965 : 0 : nValue %= 1000;
2966 : : }
2967 [ # # ]: 0 : if( nValue >= 100 )
2968 : : {
2969 : 0 : lclAppendPow10( rText, nValue / 100, 2 );
2970 : 0 : nValue %= 100;
2971 : : }
2972 [ # # ]: 0 : if( nValue > 0 )
2973 : : {
2974 : 0 : sal_Int32 nTen = nValue / 10;
2975 : 0 : sal_Int32 nOne = nValue % 10;
2976 [ # # ]: 0 : if( nTen >= 1 )
2977 : : {
2978 [ # # ]: 0 : if( nTen >= 3 )
2979 : 0 : lclAppendDigit( rText, nTen );
2980 [ # # ]: 0 : else if( nTen == 2 )
2981 : 0 : rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_20) );
2982 : 0 : rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_10) );
2983 : : }
2984 [ # # ][ # # ]: 0 : if( (nTen > 0) && (nOne == 1) )
2985 : 0 : rText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_11) );
2986 [ # # ]: 0 : else if( nOne > 0 )
2987 : 0 : lclAppendDigit( rText, nOne );
2988 : : }
2989 : 0 : }
2990 : :
2991 : : } // namespace
2992 : :
2993 : : // ----------------------------------------------------------------------------
2994 : :
2995 : 0 : void ScInterpreter::ScBahtText()
2996 : : {
2997 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBahtText" );
2998 : 0 : sal_uInt8 nParamCount = GetByte();
2999 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 1 ) )
3000 : : {
3001 [ # # ]: 0 : double fValue = GetDouble();
3002 [ # # ]: 0 : if( nGlobalError )
3003 : : {
3004 [ # # ]: 0 : PushError( nGlobalError);
3005 : 0 : return;
3006 : : }
3007 : :
3008 : : // sign
3009 : 0 : bool bMinus = fValue < 0.0;
3010 : 0 : fValue = fabs( fValue );
3011 : :
3012 : : // round to 2 digits after decimal point, fValue contains Satang as integer
3013 : 0 : fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 );
3014 : :
3015 : : // split Baht and Satang
3016 : 0 : double fBaht = 0.0;
3017 : 0 : sal_Int32 nSatang = 0;
3018 : 0 : lclSplitBlock( fBaht, nSatang, fValue, 100.0 );
3019 : :
3020 : 0 : rtl::OStringBuffer aText;
3021 : :
3022 : : // generate text for Baht value
3023 [ # # ]: 0 : if( fBaht == 0.0 )
3024 : : {
3025 [ # # ]: 0 : if( nSatang == 0 )
3026 [ # # ]: 0 : aText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_0) );
3027 : : }
3028 [ # # ]: 0 : else while( fBaht > 0.0 )
3029 : : {
3030 : 0 : rtl::OStringBuffer aBlock;
3031 : 0 : sal_Int32 nBlock = 0;
3032 : 0 : lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 );
3033 [ # # ]: 0 : if( nBlock > 0 )
3034 [ # # ]: 0 : lclAppendBlock( aBlock, nBlock );
3035 : : // add leading "million", if there will come more blocks
3036 [ # # ]: 0 : if( fBaht > 0.0 )
3037 : : aBlock.insert(
3038 [ # # ]: 0 : 0, rtl::OString(RTL_CONSTASCII_STRINGPARAM(UTF8_TH_1E6)));
3039 : :
3040 [ # # ]: 0 : aText.insert(0, aBlock.makeStringAndClear());
3041 : 0 : }
3042 [ # # ]: 0 : if (aText.getLength() > 0)
3043 [ # # ]: 0 : aText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_BAHT) );
3044 : :
3045 : : // generate text for Satang value
3046 [ # # ]: 0 : if( nSatang == 0 )
3047 : : {
3048 [ # # ]: 0 : aText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_DOT0) );
3049 : : }
3050 : : else
3051 : : {
3052 [ # # ]: 0 : lclAppendBlock( aText, nSatang );
3053 [ # # ]: 0 : aText.append( RTL_CONSTASCII_STRINGPARAM(UTF8_TH_SATANG) );
3054 : : }
3055 : :
3056 : : // add the minus sign
3057 [ # # ]: 0 : if( bMinus )
3058 : : aText.insert(
3059 [ # # ]: 0 : 0, rtl::OString(RTL_CONSTASCII_STRINGPARAM(UTF8_TH_MINUS)));
3060 : :
3061 [ # # ][ # # ]: 0 : PushString( rtl::OStringToOUString(aText.makeStringAndClear(), RTL_TEXTENCODING_UTF8) );
[ # # ][ # # ]
3062 : : }
3063 : : }
3064 : :
3065 : : // ============================================================================
3066 : :
3067 : 0 : void ScInterpreter::ScGetPivotData()
3068 : : {
3069 : : RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" );
3070 : 0 : sal_uInt8 nParamCount = GetByte();
3071 : :
3072 [ # # ]: 0 : if ( MustHaveParamCount( nParamCount, 2, 30 ) )
3073 : : {
3074 : : // there must be an even number of args
3075 : : // target, ref, then field/item pairs
3076 [ # # ]: 0 : if( (nParamCount % 2) == 1)
3077 : : goto failed;
3078 : :
3079 : 0 : bool bOldSyntax = false;
3080 [ # # ]: 0 : if ( nParamCount == 2 )
3081 : : {
3082 : : // if the first parameter is a ref, assume old syntax
3083 [ # # ]: 0 : StackVar eFirstType = GetStackType( 2 );
3084 [ # # ][ # # ]: 0 : if ( eFirstType == svSingleRef || eFirstType == svDoubleRef )
3085 : 0 : bOldSyntax = true;
3086 : : }
3087 : :
3088 : 0 : ScDPGetPivotDataField aTarget; // target field, and returns result
3089 [ # # ]: 0 : std::vector< ScDPGetPivotDataField > aFilters;
3090 [ # # ]: 0 : String aFilterList;
3091 [ # # ]: 0 : if ( bOldSyntax )
3092 [ # # ][ # # ]: 0 : aFilterList = GetString(); // old syntax: second parameter is list of constraints
3093 : : else
3094 : : {
3095 : : // new syntax: separate name/value pairs
3096 : :
3097 : 0 : sal_uInt16 nFilterCount = nParamCount / 2 - 1;
3098 [ # # ]: 0 : aFilters.resize( nFilterCount );
3099 : :
3100 : 0 : sal_uInt16 i = nFilterCount;
3101 [ # # ]: 0 : while( i-- > 0 )
3102 : : {
3103 : : //! should allow numeric constraint values
3104 : 0 : aFilters[i].mbValIsStr = true;
3105 [ # # ][ # # ]: 0 : aFilters[i].maValStr = GetString();
3106 : :
3107 [ # # ][ # # ]: 0 : aFilters[i].maFieldName = GetString();
3108 : : }
3109 : : }
3110 : :
3111 : : // common to both syntaxes: a reference to the data pilot table
3112 : :
3113 : 0 : ScRange aBlock;
3114 [ # # # ]: 0 : switch ( GetStackType() )
[ # # ]
3115 : : {
3116 : : case svDoubleRef :
3117 [ # # ]: 0 : PopDoubleRef( aBlock );
3118 : 0 : break;
3119 : :
3120 : : case svSingleRef :
3121 : : {
3122 : 0 : ScAddress aAddr;
3123 [ # # ]: 0 : PopSingleRef( aAddr );
3124 : 0 : aBlock = aAddr;
3125 : : break;
3126 : : }
3127 : : default:
3128 : : goto failed;
3129 : : }
3130 : : // NOTE : MS Excel docs claim to use the 'most recent' which is not
3131 : : // exactly the same as what we do in ScDocument::GetDPAtBlock
3132 : : // However we do need to use GetDPABlock
3133 [ # # ]: 0 : ScDPObject* pDPObj = pDok->GetDPAtBlock ( aBlock );
3134 [ # # ]: 0 : if( NULL == pDPObj)
3135 : : goto failed;
3136 : :
3137 [ # # ]: 0 : if ( bOldSyntax )
3138 : : {
3139 : : // fill aFilters / aTarget from aFilterList string
3140 [ # # ][ # # ]: 0 : if ( !pDPObj->ParseFilters( aTarget, aFilters, aFilterList ) )
[ # # ]
3141 : : goto failed;
3142 : : }
3143 : : else
3144 [ # # ][ # # ]: 0 : aTarget.maFieldName = GetString(); // new syntax: first parameter is data field name
3145 : :
3146 [ # # ][ # # ]: 0 : if( pDPObj->GetPivotData( aTarget, aFilters ) )
3147 : : {
3148 [ # # ]: 0 : if( aTarget.mbValIsStr )
3149 [ # # ][ # # ]: 0 : PushString( aTarget.maValStr );
[ # # ]
3150 : : else
3151 [ # # ]: 0 : PushDouble( aTarget.mnValNum );
3152 : 0 : return;
3153 [ # # ]: 0 : }
[ # # # ]
[ # # # ]
[ # # # ]
3154 : : }
3155 : :
3156 : : failed :
3157 : 0 : PushError( errNoRef );
3158 : : }
3159 : :
3160 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|