File indexing completed on 2024-05-12 16:35:29

0001 /* This file is part of the KDE project
0002    Copyright (C) 1998-2002 The KSpread Team <calligra-devel@kde.org>
0003    Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
0004    Copyright 2007 Sascha Pfau <MrPeacock@gmail.com>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; only
0009    version 2 of the License.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019    Boston, MA 02110-1301, USA.
0020 */
0021 
0022 // built-in engineering functions
0023 
0024 #include "EngineeringModule.h"
0025 
0026 #include "Function.h"
0027 #include "FunctionModuleRegistry.h"
0028 #include "ValueCalc.h"
0029 #include "ValueConverter.h"
0030 
0031 // used by the CONVERT function
0032 #include <QMap>
0033 
0034 // these are needed for complex functions, while we handle them in the old way
0035 #include <math.h>
0036 
0037 #ifndef M_LN2l
0038 #define M_LN2l 0.6931471805599453094172321214581766L
0039 #endif
0040 
0041 using namespace Calligra::Sheets;
0042 
0043 // prototypes (sort alphabetically)
0044 Value func_base(valVector args, ValueCalc *calc, FuncExtra *);
0045 Value func_besseli(valVector args, ValueCalc *calc, FuncExtra *);
0046 Value func_besselj(valVector args, ValueCalc *calc, FuncExtra *);
0047 Value func_besselk(valVector args, ValueCalc *calc, FuncExtra *);
0048 Value func_bessely(valVector args, ValueCalc *calc, FuncExtra *);
0049 Value func_bin2dec(valVector args, ValueCalc *calc, FuncExtra *);
0050 Value func_bin2oct(valVector args, ValueCalc *calc, FuncExtra *);
0051 Value func_bin2hex(valVector args, ValueCalc *calc, FuncExtra *);
0052 Value func_complex(valVector args, ValueCalc *calc, FuncExtra *);
0053 Value func_complex_imag(valVector args, ValueCalc *calc, FuncExtra *);
0054 Value func_complex_real(valVector args, ValueCalc *calc, FuncExtra *);
0055 Value func_convert(valVector args, ValueCalc *calc, FuncExtra *);
0056 Value func_dec2hex(valVector args, ValueCalc *calc, FuncExtra *);
0057 Value func_dec2oct(valVector args, ValueCalc *calc, FuncExtra *);
0058 Value func_dec2bin(valVector args, ValueCalc *calc, FuncExtra *);
0059 Value func_decimal(valVector args, ValueCalc *calc, FuncExtra *);
0060 Value func_delta(valVector args, ValueCalc *calc, FuncExtra *);
0061 Value func_erf(valVector args, ValueCalc *calc, FuncExtra *);
0062 Value func_erfc(valVector args, ValueCalc *calc, FuncExtra *);
0063 Value func_gestep(valVector args, ValueCalc *calc, FuncExtra *);
0064 Value func_hex2dec(valVector args, ValueCalc *calc, FuncExtra *);
0065 Value func_hex2bin(valVector args, ValueCalc *calc, FuncExtra *);
0066 Value func_hex2oct(valVector args, ValueCalc *calc, FuncExtra *);
0067 Value func_imabs(valVector args, ValueCalc *calc, FuncExtra *);
0068 Value func_imargument(valVector args, ValueCalc *calc, FuncExtra *);
0069 Value func_imconjugate(valVector args, ValueCalc *calc, FuncExtra *);
0070 Value func_imcos(valVector args, ValueCalc *calc, FuncExtra *);
0071 Value func_imcosh(valVector args, ValueCalc *calc, FuncExtra *);
0072 Value func_imcot(valVector args, ValueCalc *calc, FuncExtra *);
0073 Value func_imcsc(valVector args, ValueCalc *calc, FuncExtra *);
0074 Value func_imcsch(valVector args, ValueCalc *calc, FuncExtra *);
0075 Value func_imdiv(valVector args, ValueCalc *calc, FuncExtra *);
0076 Value func_imexp(valVector args, ValueCalc *calc, FuncExtra *);
0077 Value func_imln(valVector args, ValueCalc *calc, FuncExtra *);
0078 Value func_imlog2(valVector args, ValueCalc *calc, FuncExtra *);
0079 Value func_imlog10(valVector args, ValueCalc *calc, FuncExtra *);
0080 Value func_impower(valVector args, ValueCalc *calc, FuncExtra *);
0081 Value func_improduct(valVector args, ValueCalc *calc, FuncExtra *);
0082 Value func_imsec(valVector args, ValueCalc *calc, FuncExtra *);
0083 Value func_imsech(valVector args, ValueCalc *calc, FuncExtra *);
0084 Value func_imsin(valVector args, ValueCalc *calc, FuncExtra *);
0085 Value func_imsinh(valVector args, ValueCalc *calc, FuncExtra *);
0086 Value func_imsqrt(valVector args, ValueCalc *calc, FuncExtra *);
0087 Value func_imsub(valVector args, ValueCalc *calc, FuncExtra *);
0088 Value func_imsum(valVector args, ValueCalc *calc, FuncExtra *);
0089 Value func_imtan(valVector args, ValueCalc *calc, FuncExtra *);
0090 Value func_imtanh(valVector args, ValueCalc *calc, FuncExtra *);
0091 Value func_oct2dec(valVector args, ValueCalc *calc, FuncExtra *);
0092 Value func_oct2bin(valVector args, ValueCalc *calc, FuncExtra *);
0093 Value func_oct2hex(valVector args, ValueCalc *calc, FuncExtra *);
0094 
0095 
0096 CALLIGRA_SHEETS_EXPORT_FUNCTION_MODULE("kspreadengineeringmodule.json", EngineeringModule)
0097 
0098 
0099 EngineeringModule::EngineeringModule(QObject* parent, const QVariantList&)
0100         : FunctionModule(parent)
0101 {
0102     Function *f;
0103 
0104     f = new Function("BASE",        func_base);     // Calligra Sheets-specific, like in Quattro-Pro
0105     f->setParamCount(1, 3);
0106     add(f);
0107     f = new Function("BESSELI",     func_besseli);
0108     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELI");
0109     f->setParamCount(2);
0110     add(f);
0111     f = new Function("BESSELJ",     func_besselj);
0112     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELJ");
0113     f->setParamCount(2);
0114     add(f);
0115     f = new Function("BESSELK",     func_besselk);
0116     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELK");
0117     f->setParamCount(2);
0118     add(f);
0119     f = new Function("BESSELY",     func_bessely);
0120     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBESSELY");
0121     f->setParamCount(2);
0122     add(f);
0123     f = new Function("BIN2DEC",     func_bin2dec);
0124     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2DEC");
0125     add(f);
0126     f = new Function("BIN2OCT",     func_bin2oct);
0127     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2OCT");
0128     f->setParamCount(1, 2);
0129     add(f);
0130     f = new Function("BIN2HEX",     func_bin2hex);
0131     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETBIN2HEX");
0132     f->setParamCount(1, 2);
0133     add(f);
0134     f = new Function("COMPLEX",     func_complex);
0135     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOMPLEX");
0136     f->setParamCount(2, 3);
0137     add(f);
0138     f = new Function("CONVERT",     func_convert);
0139     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCONVERT");
0140     f->setParamCount(3);
0141     add(f);
0142     f = new Function("DEC2HEX",     func_dec2hex);
0143     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2HEX");
0144     f->setParamCount(1, 2);
0145     add(f);
0146     f = new Function("DEC2BIN",     func_dec2bin);
0147     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2BIN");
0148     f->setParamCount(1, 2);
0149     add(f);
0150     f = new Function("DEC2OCT",     func_dec2oct);
0151     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDEC2OCT");
0152     f->setParamCount(1, 2);
0153     add(f);
0154     f = new Function("DECIMAL",     func_decimal);
0155     f->setParamCount(2);
0156     add(f);
0157     f = new Function("DELTA",       func_delta);
0158     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDELTA");
0159     f->setParamCount(1, 2);
0160     add(f);
0161     f = new Function("ERF",         func_erf);
0162     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETERF");
0163     f->setParamCount(1, 2);
0164     add(f);
0165     f = new Function("ERFC",        func_erfc);
0166     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETERFC");
0167     f->setParamCount(1, 2);
0168     add(f);
0169     f = new Function("GESTEP",      func_gestep);
0170     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETGESTEP");
0171     f->setParamCount(1, 2);
0172     add(f);
0173     f = new Function("HEX2BIN",     func_hex2bin);
0174     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2BIN");
0175     f->setParamCount(1, 2);
0176     add(f);
0177     f = new Function("HEX2DEC",     func_hex2dec);
0178     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2DEC");
0179     add(f);
0180     f = new Function("HEX2OCT",     func_hex2oct);
0181     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETHEX2OCT");
0182     f->setParamCount(1, 2);
0183     add(f);
0184     f = new Function("IMABS",       func_imabs);
0185     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMABS");
0186     add(f);
0187     f = new Function("IMAGINARY",   func_complex_imag);
0188     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMAGINARY");
0189     add(f);
0190     f = new Function("IMARGUMENT",  func_imargument);
0191     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMARGUMENT");
0192     add(f);
0193     f = new Function("IMCONJUGATE", func_imconjugate);
0194     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMCONJUGATE");
0195     add(f);
0196     f = new Function("IMCOS",       func_imcos);
0197     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMCOS");
0198     add(f);
0199     f = new Function("IMCOSH",      func_imcosh);
0200     add(f);
0201     f = new Function("IMCOT",       func_imcot);
0202     add(f);
0203     f = new Function("IMCSC",       func_imcsc);
0204     add(f);
0205     f = new Function("IMCSCH",       func_imcsch);
0206     add(f);
0207     f = new Function("IMDIV",       func_imdiv);
0208     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMDIV");
0209     f->setParamCount(2);
0210     f->setAcceptArray();
0211     add(f);
0212     f = new Function("IMEXP",       func_imexp);
0213     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMEXP");
0214     add(f);
0215     f = new Function("IMLN",        func_imln);
0216     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLN");
0217     add(f);
0218     f = new Function("IMLOG2",      func_imlog2);
0219     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLOG2");
0220     add(f);
0221     f = new Function("IMLOG10",     func_imlog10);
0222     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMLOG10");
0223     add(f);
0224     f = new Function("IMPOWER",     func_impower);
0225     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMPOWER");
0226     f->setParamCount(2);
0227     add(f);
0228     f = new Function("IMPRODUCT",   func_improduct);
0229     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMPRODUCT");
0230     f->setParamCount(1, -1);
0231     f->setAcceptArray();
0232     add(f);
0233     f = new Function("IMREAL",      func_complex_real);
0234     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMREAL");
0235     add(f);
0236     f = new Function("IMSEC",       func_imsec);
0237     add(f);
0238     f = new Function("IMSECH",       func_imsech);
0239     add(f);
0240     f = new Function("IMSIN",       func_imsin);
0241     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSIN");
0242     add(f);
0243     f = new Function("IMSINH",      func_imsinh);
0244     add(f);
0245     f = new Function("IMSQRT",      func_imsqrt);
0246     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSQRT");
0247     add(f);
0248     f = new Function("IMSUB",       func_imsub);
0249     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSUB");
0250     f->setParamCount(2);
0251     f->setAcceptArray();
0252     add(f);
0253     f = new Function("IMSUM",       func_imsum);
0254     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETIMSUM");
0255     f->setParamCount(1, -1);
0256     f->setAcceptArray();
0257     add(f);
0258     f = new Function("IMTAN",       func_imtan);
0259     add(f);
0260     f = new Function("IMTANH",      func_imtanh);
0261     add(f);
0262     f = new Function("OCT2BIN",     func_oct2bin);
0263     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2BIN");
0264     f->setParamCount(1, 2);
0265     add(f);
0266     f = new Function("OCT2DEC",     func_oct2dec);
0267     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2DEC");
0268     add(f);
0269     f = new Function("OCT2HEX",     func_oct2hex);
0270     f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETOCT2HEX");
0271     f->setParamCount(1, 2);
0272     add(f);
0273 }
0274 
0275 QString EngineeringModule::descriptionFileName() const
0276 {
0277     return QString("engineering.xml");
0278 }
0279 
0280 
0281 //
0282 // Function: BASE
0283 //
0284 Value func_base(valVector args, ValueCalc *calc, FuncExtra *)
0285 {
0286     int base = 10;
0287     int minLength = 0;
0288     if (args.count() > 1)
0289         base = calc->conv()->asInteger(args[1]).asInteger();
0290     if (args.count() == 3)
0291         minLength = calc->conv()->asInteger(args[2]).asInteger();
0292 
0293     if ((base < 2) || (base > 36))
0294         return Value::errorVALUE();
0295     if (minLength < 0) minLength = 2;
0296 
0297     return calc->base(args[0], base, 0, minLength);
0298 }
0299 
0300 
0301 //
0302 // Function: BESSELI
0303 //
0304 Value func_besseli(valVector args, ValueCalc *calc, FuncExtra *)
0305 {
0306     Value x = args[0];
0307     Value y = args[1];
0308     return calc->besseli(y, x);
0309 }
0310 
0311 
0312 //
0313 // Function: BESSELJ
0314 //
0315 Value func_besselj(valVector args, ValueCalc *calc, FuncExtra *)
0316 {
0317     Value x = args[0];
0318     Value y = args[1];
0319     return calc->besselj(y, x);
0320 }
0321 
0322 
0323 //
0324 // Function: BESSELK
0325 //
0326 Value func_besselk(valVector args, ValueCalc *calc, FuncExtra *)
0327 {
0328     Value x = args[0];
0329     Value y = args[1];
0330     return calc->besselk(y, x);
0331 }
0332 
0333 
0334 //
0335 // Function: BESSELY
0336 //
0337 Value func_bessely(valVector args, ValueCalc *calc, FuncExtra *)
0338 {
0339     Value x = args[0];
0340     Value y = args[1];
0341     return calc->besseln(y, x);
0342 }
0343 
0344 
0345 //
0346 // Function: DEC2HEX
0347 //
0348 Value func_dec2hex(valVector args, ValueCalc *calc, FuncExtra *)
0349 {
0350     QRegExp rx("[0-9]+");
0351     int minLength = 0;
0352     if (args.count() > 1)
0353         // we have the optional "minimum length" argument
0354         minLength = calc->conv()->asInteger(args[1]).asInteger();
0355 
0356     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0357         // this only contains decimal digits.
0358         return calc->base(args[0], 16, 0, minLength);
0359     } else {
0360         return Value::errorVALUE();
0361     }
0362 }
0363 
0364 
0365 //
0366 // Function: DEC2OCT
0367 //
0368 Value func_dec2oct(valVector args, ValueCalc *calc, FuncExtra *)
0369 {
0370     QRegExp rx("[0-9]+");
0371     int minLength = 0;
0372     if (args.count() > 1)
0373         // we have the optional "minimum length" argument
0374         minLength = calc->conv()->asInteger(args[1]).asInteger();
0375 
0376     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0377         // this only contains decimal digits.
0378         return calc->base(args[0], 8, 0, minLength);
0379     } else {
0380         return Value::errorVALUE();
0381     }
0382 }
0383 
0384 
0385 //
0386 // Function: DEC2BIN
0387 //
0388 Value func_dec2bin(valVector args, ValueCalc *calc, FuncExtra *)
0389 {
0390     QRegExp rx("[0-9]+");
0391     int minLength = 0;
0392     if (args.count() > 1)
0393         // we have the optional "minimum length" argument
0394         minLength = calc->conv()->asInteger(args[1]).asInteger();
0395 
0396     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0397         // this only contains decimal digits.
0398         return calc->base(args[0], 2, 0, minLength);
0399     } else {
0400         return Value::errorVALUE();
0401     }
0402 }
0403 
0404 
0405 //
0406 // Function: BIN2DEC
0407 //
0408 Value func_bin2dec(valVector args, ValueCalc *calc, FuncExtra *)
0409 {
0410     return calc->fromBase(args[0], 2);
0411 }
0412 
0413 
0414 //
0415 // Function: BIN2OCT
0416 //
0417 Value func_bin2oct(valVector args, ValueCalc *calc, FuncExtra *)
0418 {
0419     QRegExp rx("[01]+");
0420     int minLength = 0;
0421     if (args.count() > 1)
0422         // we have the optional "minimum length" argument
0423         minLength = calc->conv()->asInteger(args[1]).asInteger();
0424 
0425     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0426         // this only contains 0s and 1s.
0427         return calc->base(calc->fromBase(args[0], 2), 8, 0, minLength);
0428     } else {
0429         return Value::errorVALUE();
0430     }
0431 }
0432 
0433 
0434 //
0435 // Function: BIN2HEX
0436 //
0437 Value func_bin2hex(valVector args, ValueCalc *calc, FuncExtra *)
0438 {
0439     QRegExp rx("[01]+");
0440     int minLength = 0;
0441     if (args.count() > 1)
0442         // we have the optional "minimum length" argument
0443         minLength = calc->conv()->asInteger(args[1]).asInteger();
0444 
0445     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0446         // this only contains 0s and 1s.
0447         return calc->base(calc->fromBase(args[0], 2), 16, 0, minLength);
0448     } else {
0449         return Value::errorVALUE();
0450     }
0451 
0452 }
0453 
0454 
0455 //
0456 // Function: OCT2DEC
0457 //
0458 Value func_oct2dec(valVector args, ValueCalc *calc, FuncExtra *)
0459 {
0460     return calc->fromBase(args[0], 8);
0461 }
0462 
0463 
0464 //
0465 // Function: OCT2BIN
0466 //
0467 Value func_oct2bin(valVector args, ValueCalc *calc, FuncExtra *)
0468 {
0469     QRegExp rx("[01234567]+");
0470     int minLength = 0;
0471     if (args.count() > 1)
0472         // we have the optional "minimum length" argument
0473         minLength = calc->conv()->asInteger(args[1]).asInteger();
0474 
0475     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0476         // this only contains decimal digits.
0477         return calc->base(calc->fromBase(args[0], 8), 2, 0, minLength);
0478     } else {
0479         return Value::errorVALUE();
0480     }
0481 }
0482 
0483 
0484 //
0485 // Function: OCT2HEX
0486 //
0487 Value func_oct2hex(valVector args, ValueCalc *calc, FuncExtra *)
0488 {
0489     QRegExp rx("[01234567]+");
0490     int minLength = 0;
0491     if (args.count() > 1)
0492         // we have the optional "minimum length" argument
0493         minLength = calc->conv()->asInteger(args[1]).asInteger();
0494 
0495     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0496         // this only contains decimal digits.
0497         return calc->base(calc->fromBase(args[0], 8), 16, 0, minLength);
0498     } else {
0499         return Value::errorVALUE();
0500     }
0501 }
0502 
0503 
0504 //
0505 // Function: HEX2DEC
0506 //
0507 Value func_hex2dec(valVector args, ValueCalc *calc, FuncExtra *)
0508 {
0509     return calc->fromBase(args[0], 16);
0510 }
0511 
0512 
0513 //
0514 // Function: HEX2BIN
0515 //
0516 Value func_hex2bin(valVector args, ValueCalc *calc, FuncExtra *)
0517 {
0518     QRegExp rx("[0123456789ABCDEFabcdef]+");
0519     int minLength = 0;
0520     if (args.count() > 1)
0521         // we have the optional "minimum length" argument
0522         minLength = calc->conv()->asInteger(args[1]).asInteger();
0523 
0524     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0525         // this only contains decimal digits.
0526         return calc->base(calc->fromBase(args[0], 16), 2, 0, minLength);
0527     } else {
0528         return Value::errorVALUE();
0529     }
0530 }
0531 
0532 
0533 //
0534 // Function: HEX2OCT
0535 //
0536 Value func_hex2oct(valVector args, ValueCalc *calc, FuncExtra *)
0537 {
0538     QRegExp rx("[0123456789ABCDEFabcdef]+");
0539     int minLength = 0;
0540     if (args.count() > 1)
0541         // we have the optional "minimum length" argument
0542         minLength = calc->conv()->asInteger(args[1]).asInteger();
0543 
0544     if (rx.exactMatch(calc->conv()->asString(args[0]).asString())) {
0545         // this only contains decimal digits.
0546         return calc->base(calc->fromBase(args[0], 16), 8, 0, minLength);
0547     } else {
0548         return Value::errorVALUE();
0549     }
0550 }
0551 
0552 
0553 //
0554 // Function: DECIMAL
0555 //
0556 Value func_decimal(valVector args, ValueCalc *calc, FuncExtra *)
0557 {
0558     QString text = calc->conv()->asString(args[0]).asString();
0559     text.remove(QLatin1Char(' '));
0560     text.remove(QLatin1Char('\t'));
0561     int radix = calc->conv()->asInteger(args[1]).asInteger();
0562     if (radix == 16) {
0563         if (text.startsWith(QLatin1String("0x"), Qt::CaseInsensitive)) {
0564             text.remove(0, 2);
0565         }
0566         if (text.endsWith(QLatin1Char('h'), Qt::CaseInsensitive)) {
0567             text.chop(1);  // all but the last char
0568         }
0569     }
0570     if (radix == 2) {
0571         if (text.endsWith(QLatin1Char('b'), Qt::CaseInsensitive)) {
0572             text.chop(1);  // all but the last char
0573         }
0574     }
0575 
0576     return calc->fromBase(Value(text), radix);
0577 }
0578 
0579 //
0580 // convert prefix
0581 //
0582 
0583 // check if unit may contain prefix, for example "kPa" is "Pa" with
0584 // return prefix factor found in unit, or 1.0 for no prefix
0585 // also modify the unit, i.e stripping the prefix from it
0586 // example: "kPa" will return 1e3 and change unit into "Pa"
0587 static double kspread_convert_prefix(QMap<QString, double> map, QString& unit)
0588 {
0589     if (map.contains(unit))
0590         return 1.0;
0591 
0592     // initialize prefix mapping if necessary
0593     static QMap<QString, double> prefixMap;
0594     if (prefixMap.isEmpty()) {
0595         prefixMap[ "Y" ]  = 1e24;   // yotta
0596         prefixMap[ "Z" ]  = 1e21;   // zetta
0597         prefixMap[ "E" ]  = 1e18;   // exa
0598         prefixMap[ "P" ]  = 1e15;   // peta
0599         prefixMap[ "T" ]  = 1e12;   // tera
0600         prefixMap[ "G" ]  = 1e9;    // giga
0601         prefixMap[ "M" ]  = 1e6;    // mega
0602         prefixMap[ "k" ]  = 1e3;    // kilo
0603         prefixMap[ "h" ]  = 1e2;    // hecto
0604         prefixMap[ "e" ]  = 1e1;    // deka
0605         prefixMap[ "da" ] = 1e1;    // deka
0606         prefixMap[ "d" ]  = 1e-1;   // deci
0607         prefixMap[ "c" ]  = 1e-2;   // centi
0608         prefixMap[ "m" ]  = 1e-3;   // milli
0609         prefixMap[ "u" ]  = 1e-6;   // micro
0610         prefixMap[ "n" ]  = 1e-9;   // nano
0611         prefixMap[ "p" ]  = 1e-12;  // pico
0612         prefixMap[ "f" ]  = 1e-15;  // femto
0613         prefixMap[ "a" ]  = 1e-18;  // atto
0614         prefixMap[ "z" ]  = 1e-21;  // zepto
0615         prefixMap[ "y" ]  = 1e-24;  // yocto
0616 
0617         // binary prefixes
0618         prefixMap[ "ki" ]  = 1024.0                      ;  // kibi
0619         prefixMap[ "Mi" ]  = 1048576.0                   ;  // mebi
0620         prefixMap[ "Gi" ]  = 1073741824.0                ;  // gibi
0621         prefixMap[ "Ti" ]  = 1099511627776.0             ;  // tebi
0622         prefixMap[ "Pi" ]  = 1125899906842624.0          ;  // pebi
0623         prefixMap[ "Ei" ]  = 1152921504606846976.0       ;  // exbi
0624         prefixMap[ "Zi" ]  = 1180591620717411303424.0    ;  // zebi
0625         prefixMap[ "Yi" ]  = 1208925819614629174706176.0 ;  // yobi
0626     }
0627 
0628     // check for possible prefix
0629     QString prefix = unit.left(2).toLatin1();
0630 
0631     if (prefixMap.contains(prefix)) {
0632         unit.remove(0, 2);
0633         return prefixMap[prefix];
0634     } else if (prefixMap.contains(prefix.left(1))) {
0635         unit.remove(0, 1);
0636         return prefixMap[prefix.left(1)];
0637     }
0638     // fail miserably
0639     return 0.0;
0640 }
0641 
0642 
0643 //
0644 // convert masses
0645 //
0646 static bool kspread_convert_mass(const QString& fromUnit,
0647                                  const QString& toUnit, double value, double& result)
0648 {
0649     static QMap<QString, double> massMap;
0650 
0651     // first-time initialization
0652     if (massMap.isEmpty()) {
0653         massMap[ "g" ]        = 1.0; // Gram (the reference )
0654 
0655         massMap[ "sg" ]       = 6.8522050005347800E-05;          // Pieces
0656         massMap[ "lbm" ]      = 2.2046229146913400E-03;          // Pound
0657         massMap[ "u" ]        = 6.0221370000000000E23;           // U (atomic mass)
0658         massMap[ "ozm" ]      = 3.5273971800362700E-02;          // Ounce
0659         massMap[ "stone" ]    = 1.574730e-04;                    // Stone
0660         massMap[ "ton" ]      = 1.102311e-06;                    // Ton
0661         massMap[ "grain" ]    = 1.543236E01;                     // Grain
0662         massMap[ "pweight" ]  = 7.054792E-01;                    // Pennyweight
0663         massMap[ "hweight" ]  = 1.968413E-05;                    // Hundredweight
0664         massMap[ "shweight" ] = 2.204623E-05;                    // Shorthundredweight
0665         massMap[ "uk_ton" ]   = 1.0 / 2240 * 2.2046229146913400E-03; // It's long ton or Imperial ton, 2240 lbm.
0666     }
0667 
0668     QString fromU = fromUnit;
0669     QString toU = toUnit;
0670     double fromPrefix = kspread_convert_prefix(massMap, fromU);
0671     double toPrefix = kspread_convert_prefix(massMap, toU);
0672     if (fromPrefix == 0.0) return false;
0673     if (toPrefix == 0.0) return false;
0674     if (!massMap.contains(fromU)) return false;
0675     if (!massMap.contains(toU)) return false;
0676 
0677     result = value * fromPrefix * massMap[toU] / (massMap[fromU] * toPrefix);
0678 
0679     return true;
0680 }
0681 
0682 
0683 //
0684 // convert distances
0685 //
0686 static bool kspread_convert_distance(const QString& fromUnit,
0687                                      const QString& toUnit, double value, double& result)
0688 {
0689     static QMap<QString, double> distanceMap;
0690 
0691     // first-time initialization
0692     if (distanceMap.isEmpty()) {
0693         distanceMap[ "m" ]          = 1.0;  // meter (the reference)
0694 
0695         distanceMap[ "ang" ]        = 1e10;                        // Angstrom
0696         distanceMap[ "ell" ]        = 1.0 / (45.0 * 0.0254);       // Ell, exactly 45 international inches
0697         distanceMap[ "ft" ]         = 1.0 / (12.0 * 0.0254);       // feet
0698         distanceMap[ "in" ]         = 1.0 / 0.0254;                // inch
0699         distanceMap[ "lightyear" ]  = 1.057023455773293e-16;       // lightyear
0700         distanceMap[ "ly" ]         = 1.057023455773293e-16;       // lightyear
0701         distanceMap[ "mi" ]         = 6.2137119223733397e-4;       // mile
0702         distanceMap[ "Nmi" ]        = 5.3995680345572354e-04;      // nautical mile
0703         distanceMap[ "parsec" ]     = 3.240779e-17;                // Parsec
0704         distanceMap[ "pc" ]         = 3.240779e-17;                // Parsec
0705         distanceMap[ "Pica" ]       = 1.0 * 72 / 0.0254;           // Pica (1/72) inch
0706         distanceMap[ "statute_mi" ] = 1.0 / (6336000.0 / 3937.0);  // U.S. survey mile aka U.S. statute mile
0707         distanceMap[ "yd" ]         = 1.0 / (3.0 * 12.0 * 0.0254); // yard
0708     }
0709 
0710     QString fromU = fromUnit;
0711     QString toU = toUnit;
0712     double fromPrefix = kspread_convert_prefix(distanceMap, fromU);
0713     double toPrefix = kspread_convert_prefix(distanceMap, toU);
0714     if (fromPrefix == 0.0) return false;
0715     if (toPrefix == 0.0) return false;
0716     if (!distanceMap.contains(fromU)) return false;
0717     if (!distanceMap.contains(toU)) return false;
0718 
0719     result = value * fromPrefix * distanceMap[toU] / (distanceMap[fromU] * toPrefix);
0720 
0721     return true;
0722 }
0723 
0724 
0725 //
0726 // convert pressures
0727 //
0728 static bool kspread_convert_pressure(const QString& fromUnit,
0729                                      const QString& toUnit, double value, double& result)
0730 {
0731     static QMap<QString, double> pressureMap;
0732 
0733     // first-time initialization
0734     if (pressureMap.isEmpty()) {
0735         pressureMap[ "Pa" ]   = 1.0;
0736 
0737         pressureMap[ "atm" ]  = 0.9869233e-5;  // Atmosphere
0738         pressureMap[ "atm" ]  = 0.9869233e-5;  // Atmosphere
0739         pressureMap[ "mmHg" ] = 0.00750061708; // mm of Mercury
0740         pressureMap[ "psi" ]  = 1 / 6894.754;  // Pounds per square inch
0741         pressureMap[ "Torr" ] = 1 / 133.32237; // Torr, exactly 101325/760 Pa
0742     }
0743 
0744     QString fromU = fromUnit;
0745     QString toU = toUnit;
0746     double fromPrefix = kspread_convert_prefix(pressureMap, fromU);
0747     double toPrefix = kspread_convert_prefix(pressureMap, toU);
0748     if (fromPrefix == 0.0) return false;
0749     if (toPrefix == 0.0) return false;
0750     if (!pressureMap.contains(fromU)) return false;
0751     if (!pressureMap.contains(toU)) return false;
0752 
0753     result = value * fromPrefix * pressureMap[toU] / (pressureMap[fromU] * toPrefix);
0754 
0755     return true;
0756 }
0757 
0758 
0759 //
0760 // convert forces
0761 //
0762 static bool kspread_convert_force(const QString& fromUnit,
0763                                   const QString& toUnit, double value, double& result)
0764 {
0765     static QMap<QString, double> forceMap;
0766 
0767     // first-time initialization
0768     if (forceMap.isEmpty()) {
0769         forceMap[ "N" ]      = 1.0;          // Newton (reference)
0770 
0771         forceMap[ "dy" ]     = 1.0e5;        // dyne
0772         forceMap[ "dyn" ]    = 1.0e5;        // dyne
0773         forceMap[ "lbf" ]    = 1.0 / 4.448222; // Pound force (see "lbm" for pound mass)
0774         forceMap[ "pond" ]   = 1.019716e2;   // pond
0775     }
0776 
0777     QString fromU = fromUnit;
0778     QString toU = toUnit;
0779     double fromPrefix = kspread_convert_prefix(forceMap, fromU);
0780     double toPrefix = kspread_convert_prefix(forceMap, toU);
0781     if (fromPrefix == 0.0) return false;
0782     if (toPrefix == 0.0) return false;
0783     if (!forceMap.contains(fromU)) return false;
0784     if (!forceMap.contains(toU)) return false;
0785 
0786     result = value * fromPrefix * forceMap[toU] / (forceMap[fromU] * toPrefix);
0787 
0788     return true;
0789 }
0790 
0791 
0792 //
0793 // convert energies
0794 //
0795 static bool kspread_convert_energy(const QString& fromUnit,
0796                                    const QString& toUnit, double value, double& result)
0797 {
0798     static QMap<QString, double> energyMap;
0799 
0800     // first-time initialization
0801     if (energyMap.isEmpty()) {
0802         energyMap[ "J" ]   = 1.0;                 // Joule (the reference)
0803 
0804         energyMap[ "e" ]   = 1.0e7;               // erg
0805         energyMap[ "c" ]   = 0.239006249473467;   // thermodynamical calorie
0806         energyMap[ "cal" ] = 0.238846190642017;   // calorie
0807         energyMap[ "eV" ]  = 6.241457e+18;        // electronvolt
0808         energyMap[ "HPh" ] = 3.72506111e-7;       // horsepower-hour
0809         energyMap[ "Wh" ]  = 0.000277778;         // watt-hour
0810         energyMap[ "flb" ] = 23.73042222;
0811         energyMap[ "BTU" ] = 9.47815067349015e-4; // British Thermal Unit
0812     }
0813 
0814     QString fromU = fromUnit;
0815     QString toU = toUnit;
0816     double fromPrefix = kspread_convert_prefix(energyMap, fromU);
0817     double toPrefix = kspread_convert_prefix(energyMap, toU);
0818     if (fromPrefix == 0.0) return false;
0819     if (toPrefix == 0.0) return false;
0820     if (!energyMap.contains(fromU)) return false;
0821     if (!energyMap.contains(toU)) return false;
0822 
0823     result = value * fromPrefix * energyMap[toU] / (energyMap[fromU] * toPrefix);
0824 
0825     return true;
0826 }
0827 
0828 
0829 //
0830 // convert powers
0831 //
0832 static bool kspread_convert_power(const QString& fromUnit,
0833                                   const QString& toUnit, double value, double& result)
0834 {
0835     static QMap<QString, double> powerMap;
0836 
0837     // first-time initialization
0838     if (powerMap.isEmpty()) {
0839         powerMap[ "W" ]   = 1.0; // Watt (the reference)
0840 
0841 //     powerMap[ "HP" ]  = 1.341022e-3; // Horsepower
0842         powerMap[ "HP" ]  = 1.0 / 745.701; // Horsepower (UK)
0843         powerMap[ "PS" ]  = 1.359622e-3; // Pferdestaerke (German)
0844     }
0845 
0846     QString fromU = fromUnit;
0847     QString toU = toUnit;
0848     double fromPrefix = kspread_convert_prefix(powerMap, fromU);
0849     double toPrefix = kspread_convert_prefix(powerMap, toU);
0850     if (fromPrefix == 0.0) return false;
0851     if (toPrefix == 0.0) return false;
0852     if (!powerMap.contains(fromU)) return false;
0853     if (!powerMap.contains(toU)) return false;
0854 
0855     result = value * fromPrefix * powerMap[toU] / (powerMap[fromU] * toPrefix);
0856 
0857     return true;
0858 }
0859 
0860 
0861 //
0862 // convert magnetism
0863 //
0864 static bool kspread_convert_magnetism(const QString& fromUnit,
0865                                       const QString& toUnit, double value, double& result)
0866 {
0867     static QMap<QString, double> magnetismMap;
0868 
0869     // first-time initialization
0870     if (magnetismMap.isEmpty()) {
0871         magnetismMap[ "T" ]   = 1.0;    // Tesla (the reference)
0872 
0873         magnetismMap[ "ga" ]  = 1.0e4;  // Gauss
0874     }
0875 
0876     QString fromU = fromUnit;
0877     QString toU = toUnit;
0878     double fromPrefix = kspread_convert_prefix(magnetismMap, fromU);
0879     double toPrefix = kspread_convert_prefix(magnetismMap, toU);
0880     if (fromPrefix == 0.0) return false;
0881     if (toPrefix == 0.0) return false;
0882     if (!magnetismMap.contains(fromU)) return false;
0883     if (!magnetismMap.contains(toU)) return false;
0884 
0885     result = value * fromPrefix * magnetismMap[toU] / (magnetismMap[fromU] * toPrefix);
0886 
0887     return true;
0888 }
0889 
0890 
0891 //
0892 // convert temperatures
0893 //
0894 static bool kspread_convert_temperature(const QString& fromUnit,
0895                                         const QString& toUnit, double value, double& result)
0896 {
0897     static QMap<QString, double> tempFactorMap;
0898     static QMap<QString, double> tempOffsetMap;
0899 
0900     // first-time initialization
0901     if (tempFactorMap.isEmpty() || tempOffsetMap.isEmpty()) {
0902         tempFactorMap[ "C" ] = 1.0; tempOffsetMap[ "C" ] = 0.0;
0903         tempFactorMap[ "F" ] = 5.0 / 9.0; tempOffsetMap[ "F" ] = -32.0;
0904         tempFactorMap[ "K" ] = 1.0; tempOffsetMap[ "K" ] = -273.15;
0905     }
0906 
0907     if (!tempFactorMap.contains(fromUnit)) return false;
0908     if (!tempOffsetMap.contains(fromUnit)) return false;
0909     if (!tempFactorMap.contains(toUnit)) return false;
0910     if (!tempOffsetMap.contains(toUnit)) return false;
0911 
0912     result = (value + tempOffsetMap[ fromUnit ]) * tempFactorMap[ fromUnit ];
0913     result = (result / tempFactorMap[ toUnit ]) - tempOffsetMap[ toUnit ];
0914 
0915     return true;
0916 }
0917 
0918 
0919 //
0920 // convert volumes
0921 //
0922 static bool kspread_convert_volume(const QString& fromUnit,
0923                                    const QString& toUnit, double value, double& result)
0924 {
0925     static QMap<QString, double> volumeMap;
0926 
0927     // first-time initialization
0928     if (volumeMap.isEmpty()) {
0929         volumeMap[ "l" ]      = 1.0;                    // Liter (the reference)
0930 
0931 //TODO ang3
0932         volumeMap[ "barrel" ] = 6.289811E-03;           // barrel
0933 //TODO bushel
0934         volumeMap[ "cup" ]    = 4.22583333333333;       // cup
0935         volumeMap[ "ft3" ]    = 3.5314666721488590e-2;  // cubic foot
0936         volumeMap[ "gal" ]    = 0.26411458333333;       // gallone
0937         volumeMap[ "in3" ]    = 6.1023744094732284e1;   // cubic inch
0938         volumeMap[ "m3" ]     = 1.0e-3;                 // cubic meter
0939         volumeMap[ "mi3" ]    = 2.3991275857892772e-13; // cubic mile
0940 //TODO MTON
0941         volumeMap[ "Nmi3" ]   = 1.5742621468581148e-13; // cubic Nautical mile
0942         volumeMap[ "oz" ]     = 33.8066666666667;       // ounce liquid
0943 //TODO Pica3
0944         volumeMap[ "pt" ]     = 2.11291666666667;       // pint
0945         volumeMap[ "qt" ]     = 1.05645833333333;       // quart
0946         volumeMap[ "GRT" ]    = 2831.6846592;           // Gross Register Ton
0947         volumeMap[ "regton" ] = volumeMap[ "GRT" ];
0948         volumeMap[ "tbs" ]    = 67.6133333333333;       // sheetspoon
0949         volumeMap[ "tsp" ]    = 202.84;                 // teaspoon
0950 //TODO tspm
0951 //TODO uk_pt
0952         volumeMap[ "yd3" ]    = 1.3079506193143922;     // cubic yard
0953 
0954     }
0955 
0956     QString fromU = fromUnit;
0957     QString toU = toUnit;
0958     double fromPrefix = kspread_convert_prefix(volumeMap, fromU);
0959     double toPrefix = kspread_convert_prefix(volumeMap, toU);
0960     if (fromPrefix == 0.0) return false;
0961     if (toPrefix == 0.0) return false;
0962     if (!volumeMap.contains(fromU)) return false;
0963     if (!volumeMap.contains(toU)) return false;
0964 
0965     result = value * fromPrefix * volumeMap[toU] / (volumeMap[fromU] * toPrefix);
0966 
0967     return true;
0968 }
0969 
0970 
0971 //
0972 // convert areas
0973 //
0974 static bool kspread_convert_area(const QString& fromUnit,
0975                                  const QString& toUnit, double value, double& result)
0976 {
0977     static QMap<QString, double> areaMap;
0978 
0979     // first-time initialization
0980     if (areaMap.isEmpty()) {
0981         areaMap[ "m2" ]    = 1.0; // square meter (the reference)
0982         areaMap[ "m^2" ]   = 1.0; // square meter (the reference)
0983 
0984         areaMap[ "acre" ]  = 4.046856e3;            // acre
0985         areaMap[ "ar" ]    = 1.0 / 100;             // are
0986         areaMap[ "ft2" ]   = 1.0763910416709722e1;  // square foot
0987         areaMap[ "ft^2" ]  = 1.0763910416709722e1;  // square foot
0988         areaMap[ "ha" ]    = 1.0e4;                 // hectare
0989         areaMap[ "in2" ]   = 1.5500031000062000e3;  // square inch
0990         areaMap[ "in^2" ]  = 1.5500031000062000e3;  // square inch
0991         areaMap[ "mi2" ]   = 3.8610215854244585e-7; // square mile
0992         areaMap[ "mi^2" ]  = 3.8610215854244585e-7; // square mile
0993         areaMap[ "Nmi2" ]  = 2.9155334959812286e-7; // square Nautical mile
0994         areaMap[ "Nmi^2" ] = 2.9155334959812286e-7; // square Nautical mile
0995         areaMap[ "yd2" ]   = 1.0936132983377078;    // square yard
0996         areaMap[ "yd^2" ]  = 1.0936132983377078;    // square yard
0997     }
0998 
0999     QString fromU = fromUnit;
1000     QString toU = toUnit;
1001     double fromPrefix = kspread_convert_prefix(areaMap, fromU);
1002     double toPrefix = kspread_convert_prefix(areaMap, toU);
1003     if (fromPrefix == 0.0) return false;
1004     if (toPrefix == 0.0) return false;
1005     if (!areaMap.contains(fromU)) return false;
1006     if (!areaMap.contains(toU)) return false;
1007 
1008     result = value * fromPrefix * areaMap[toU] / (areaMap[fromU] * toPrefix);
1009 
1010     return true;
1011 }
1012 
1013 
1014 //
1015 // convert speeds
1016 //
1017 static bool kspread_convert_speed(const QString& fromUnit,
1018                                   const QString& toUnit, double value, double& result)
1019 {
1020     static QMap<QString, double> speedMap;
1021 
1022     // first-time initialization
1023     if (speedMap.isEmpty()) {
1024         speedMap[ "m/s" ] = 1.0; // meters per second (the reference)
1025 
1026         speedMap[ "m/h" ] = 3.6e3; // meters per hour
1027         speedMap[ "mph" ] = 2.2369362920544023; // miles per hour
1028         speedMap[ "kn" ]  = 1.9438444924406048; // knot
1029     }
1030 
1031     QString fromU = fromUnit;
1032     QString toU = toUnit;
1033     double fromPrefix = kspread_convert_prefix(speedMap, fromU);
1034     double toPrefix = kspread_convert_prefix(speedMap, toU);
1035     if (fromPrefix == 0.0) return false;
1036     if (toPrefix == 0.0) return false;
1037     if (!speedMap.contains(fromU)) return false;
1038     if (!speedMap.contains(toU)) return false;
1039 
1040     result = value * fromPrefix * speedMap[toU] / (speedMap[fromU] * toPrefix);
1041 
1042     return true;
1043 }
1044 
1045 
1046 //
1047 // convert times
1048 //
1049 static bool kspread_convert_time(const QString& fromUnit,
1050                                  const QString& toUnit, double value, double& result)
1051 {
1052     static QMap<QString, double> timeMap;
1053 
1054     // first-time initialization
1055     if (timeMap.isEmpty()) {
1056         timeMap[ "s" ]   = 1.0;                          // second (the reference)
1057         timeMap[ "sec" ] = 1.0;                          // second (the reference)
1058 
1059         timeMap[ "mn" ]  = 1.0 / 60;                     // 24 hour per day
1060         timeMap[ "min" ] = 1.0 / 60;                     // 24 hour per day
1061         timeMap[ "hr" ]  = 1.0 / 3600;                   // 3600 seconds per hour
1062         timeMap[ "d" ]   = 1.0 / (3600 * 24);            // 24 hour per day
1063         timeMap[ "day" ] = 1.0 / (3600 * 24);            // 24 hour per day
1064         timeMap[ "yr" ]  = 1.0 / (3600 * 24 * 365.25);   // 24 hour per day
1065     }
1066 
1067     QString fromU = fromUnit;
1068     QString toU = toUnit;
1069     double fromPrefix = kspread_convert_prefix(timeMap, fromU);
1070     double toPrefix = kspread_convert_prefix(timeMap, toU);
1071     if (fromPrefix == 0.0) return false;
1072     if (toPrefix == 0.0) return false;
1073     if (!timeMap.contains(fromU)) return false;
1074     if (!timeMap.contains(toU)) return false;
1075 
1076     result = value * fromPrefix * timeMap[toU] / (timeMap[fromU] * toPrefix);
1077 
1078     return true;
1079 }
1080 
1081 
1082 //
1083 // convert IT
1084 //
1085 static bool kspread_convert_info(const QString& fromUnit,
1086                                  const QString& toUnit, double value, double& result)
1087 {
1088     static QMap<QString, double> infoMap;
1089 
1090     // first-time initialization
1091     if (infoMap.isEmpty()) {
1092         infoMap[ "bit" ]  = 1.0;     // bit (the reference)
1093         infoMap[ "byte" ] = 1.0 / 8; // 8 bit per byte
1094     }
1095 
1096     QString fromU = fromUnit;
1097     QString toU = toUnit;
1098     double fromPrefix = kspread_convert_prefix(infoMap, fromU);
1099     double toPrefix = kspread_convert_prefix(infoMap, toU);
1100     if (fromPrefix == 0.0) return false;
1101     if (toPrefix == 0.0) return false;
1102     if (!infoMap.contains(fromU)) return false;
1103     if (!infoMap.contains(toU)) return false;
1104 
1105     result = value * fromPrefix * infoMap[toU] / (infoMap[fromU] * toPrefix);
1106 
1107     return true;
1108 }
1109 
1110 //
1111 // Function: CONVERT
1112 //
1113 Value func_convert(valVector args, ValueCalc *calc, FuncExtra *)
1114 {
1115     // This function won't support arbitrary precision.
1116 
1117     double value = numToDouble(calc->conv()->toFloat(args[0]));
1118     QString fromUnit = calc->conv()->toString(args[1]);
1119     QString toUnit = calc->conv()->toString(args[2]);
1120 
1121     double result = value;
1122 
1123     if (!kspread_convert_mass(fromUnit, toUnit, value, result))
1124         if (!kspread_convert_distance(fromUnit, toUnit, value, result))
1125             if (!kspread_convert_pressure(fromUnit, toUnit, value, result))
1126                 if (!kspread_convert_force(fromUnit, toUnit, value, result))
1127                     if (!kspread_convert_energy(fromUnit, toUnit, value, result))
1128                         if (!kspread_convert_power(fromUnit, toUnit, value, result))
1129                             if (!kspread_convert_magnetism(fromUnit, toUnit, value, result))
1130                                 if (!kspread_convert_temperature(fromUnit, toUnit, value, result))
1131                                     if (!kspread_convert_volume(fromUnit, toUnit, value, result))
1132                                         if (!kspread_convert_area(fromUnit, toUnit, value, result))
1133                                             if (!kspread_convert_speed(fromUnit, toUnit, value, result))
1134                                                 if (!kspread_convert_time(fromUnit, toUnit, value, result))
1135                                                     if (!kspread_convert_info(fromUnit, toUnit, value, result))
1136                                                         return Value::errorNA();
1137 
1138     return Value(result);
1139 }
1140 
1141 
1142 // functions operating over complex numbers ...
1143 // these may eventually end up being merged into ValueCalc and friends
1144 // then complex numbers will be handled transparently in most functions
1145 
1146 
1147 //
1148 // Function: COMPLEX
1149 //
1150 Value func_complex(valVector args, ValueCalc *calc, FuncExtra *)
1151 {
1152     const double real = numToDouble(calc->conv()->toFloat(args[0]));
1153     const double imag = numToDouble(calc->conv()->toFloat(args[1]));
1154     return Value(complex<Number>(real, imag));
1155 }
1156 
1157 
1158 //
1159 // Function: IMAGINARY
1160 //
1161 Value func_complex_imag(valVector args, ValueCalc *calc, FuncExtra *)
1162 {
1163     return Value(calc->conv()->toComplex(args[0]).imag());
1164 }
1165 
1166 
1167 //
1168 // Function: IMREAL
1169 //
1170 Value func_complex_real(valVector args, ValueCalc *calc, FuncExtra *)
1171 {
1172     return Value(calc->conv()->toComplex(args[0]).real());
1173 }
1174 
1175 
1176 //
1177 //
1178 //
1179 void awImSum(ValueCalc *c, Value &res, Value val, Value)
1180 {
1181     const complex<Number> c1 = c->conv()->toComplex(res);
1182     const complex<Number> c2 = c->conv()->toComplex(val);
1183     res = Value(c1 + c2);
1184 }
1185 
1186 
1187 //
1188 //
1189 //
1190 void awImSub(ValueCalc *c, Value &res, Value val, Value)
1191 {
1192     const complex<Number> c1 = c->conv()->toComplex(res);
1193     const complex<Number> c2 = c->conv()->toComplex(val);
1194     res = Value(c1 - c2);
1195 }
1196 
1197 
1198 //
1199 //
1200 //
1201 void awImMul(ValueCalc *c, Value &res, Value val, Value)
1202 {
1203     const complex<Number> c1 = c->conv()->toComplex(res);
1204     const complex<Number> c2 = c->conv()->toComplex(val);
1205     res = Value(c1 * c2);
1206 }
1207 
1208 
1209 //
1210 //
1211 //
1212 void awImDiv(ValueCalc *c, Value &res, Value val, Value)
1213 {
1214     const complex<Number> c1 = c->conv()->toComplex(res);
1215     const complex<Number> c2 = c->conv()->toComplex(val);
1216     res = Value(c1 / c2);
1217 }
1218 
1219 //
1220 // Function: IMSUM
1221 //
1222 Value func_imsum(valVector args, ValueCalc *calc, FuncExtra *)
1223 {
1224     Value result;
1225     calc->arrayWalk(args, result, awImSum, Value(0));
1226     return result;
1227 }
1228 
1229 
1230 //
1231 // Function: IMSUB
1232 //
1233 Value func_imsub(valVector args, ValueCalc *calc, FuncExtra *)
1234 {
1235     Value result;
1236     if (args.count() == 1)
1237         awImSub(calc, result, args[0], Value(0));
1238     else {
1239         result = args[0];
1240         valVector vector = args.mid(1);
1241         calc->arrayWalk(vector, result, awImSub, Value(0));
1242     }
1243     return result;
1244 }
1245 
1246 
1247 //
1248 // Function: IMPRODUCT
1249 //
1250 Value func_improduct(valVector args, ValueCalc *calc, FuncExtra *)
1251 {
1252     Value result;
1253     if (args.count() == 1) {
1254         result = Value(complex<double>(1.0, 0.0));
1255         awImMul(calc, result, args[0], Value(0));
1256     } else {
1257         result = args[0];
1258         valVector vector = args.mid(1);
1259         calc->arrayWalk(vector, result, awImMul, Value(0));
1260     }
1261     return result;
1262 }
1263 
1264 
1265 //
1266 // Function: IMDIV
1267 //
1268 Value func_imdiv(valVector args, ValueCalc *calc, FuncExtra *)
1269 {
1270     Value result;
1271     if (args.count() == 1) {
1272         result = Value(complex<double>(1.0, 0.0));
1273         awImDiv(calc, result, args[0], Value(0));
1274     } else {
1275         result = args[0];
1276         valVector vector = args.mid(1);
1277         calc->arrayWalk(vector, result, awImDiv, Value(0));
1278     }
1279     return result;
1280 }
1281 
1282 
1283 //
1284 // Function: IMCONJUGATE
1285 //
1286 Value func_imconjugate(valVector args, ValueCalc *calc, FuncExtra *)
1287 {
1288     return Value(std::conj(calc->conv()->asComplex(args[0]).asComplex()));
1289 }
1290 
1291 
1292 //
1293 // Function: IMARGUMENT
1294 //
1295 Value func_imargument(valVector args, ValueCalc *calc, FuncExtra *)
1296 {
1297     return Value(std::arg(calc->conv()->asComplex(args[0]).asComplex()));
1298 }
1299 
1300 
1301 //
1302 // Function: IMABS
1303 //
1304 Value func_imabs(valVector args, ValueCalc *calc, FuncExtra *)
1305 {
1306     return Value(std::abs(calc->conv()->asComplex(args[0]).asComplex()));
1307 }
1308 
1309 
1310 //
1311 // Function: IMCOS
1312 //
1313 Value func_imcos(valVector args, ValueCalc *calc, FuncExtra *)
1314 {
1315     return Value(std::cos(calc->conv()->asComplex(args[0]).asComplex()));
1316 }
1317 
1318 
1319 //
1320 // Function: IMCOT
1321 //
1322 Value func_imcot(valVector args, ValueCalc *calc, FuncExtra*)
1323 {
1324     return Value(std::cos(calc->conv()->asComplex(args[0]).asComplex())
1325                  /std::sin(calc->conv()->asComplex(args[0]).asComplex()));
1326 }
1327 
1328 
1329 //
1330 // Function: IMCSC
1331 //
1332 Value func_imcsc(valVector args, ValueCalc *calc, FuncExtra *)
1333 {
1334     return Value(complex<Number>(1)/std::sin(calc->conv()->asComplex(args[0]).asComplex()));
1335 }
1336 
1337 
1338 //
1339 // Function: IMSEC
1340 //
1341 Value func_imsec(valVector args, ValueCalc *calc, FuncExtra *)
1342 {
1343     return Value(complex<Number>(1)/std::cos(calc->conv()->asComplex(args[0]).asComplex()));
1344 }
1345 
1346 
1347 //
1348 // Function: IMSIN
1349 //
1350 Value func_imsin(valVector args, ValueCalc *calc, FuncExtra *)
1351 {
1352     return Value(std::sin(calc->conv()->asComplex(args[0]).asComplex()));
1353 }
1354 
1355 
1356 //
1357 // Function: IMTAN
1358 //
1359 Value func_imtan(valVector args, ValueCalc *calc, FuncExtra*)
1360 {
1361     return Value(std::tan(calc->conv()->asComplex(args[0]).asComplex()));
1362 }
1363 
1364 
1365 //
1366 // Function: IMCOSH
1367 //
1368 Value func_imcosh(valVector args, ValueCalc *calc, FuncExtra*)
1369 {
1370     return Value(std::cosh(calc->conv()->asComplex(args[0]).asComplex()));
1371 }
1372 
1373 
1374 //
1375 // Function: IMCSCH
1376 //
1377 Value func_imcsch(valVector args, ValueCalc *calc, FuncExtra*)
1378 {
1379     return Value(complex<Number>(1)/std::sinh(calc->conv()->asComplex(args[0]).asComplex()));
1380 }
1381 
1382 
1383 //
1384 // Function: IMSECH
1385 //
1386 Value func_imsech(valVector args, ValueCalc *calc, FuncExtra *)
1387 {
1388     return Value(complex<Number>(1)/std::cosh(calc->conv()->asComplex(args[0]).asComplex()));
1389 }
1390 
1391 
1392 //
1393 // Function: IMSINH
1394 //
1395 Value func_imsinh(valVector args, ValueCalc *calc, FuncExtra*)
1396 {
1397     return Value(std::sinh(calc->conv()->asComplex(args[0]).asComplex()));
1398 }
1399 
1400 
1401 //
1402 // Function: IMTANH
1403 //
1404 Value func_imtanh(valVector args, ValueCalc *calc, FuncExtra*)
1405 {
1406     return Value(std::tanh(calc->conv()->asComplex(args[0]).asComplex()));
1407 }
1408 
1409 
1410 //
1411 // Function: IMLN
1412 //
1413 Value func_imln(valVector args, ValueCalc *calc, FuncExtra *)
1414 {
1415     return Value(std::log(calc->conv()->asComplex(args[0]).asComplex()));
1416 }
1417 
1418 
1419 //
1420 // Function: IMLOG2
1421 //
1422 Value func_imlog2(valVector args, ValueCalc *calc, FuncExtra *)
1423 {
1424     return Value(std::log(calc->conv()->toComplex(args[0])) / static_cast<Number>(double(M_LN2l)));
1425 }
1426 
1427 
1428 //
1429 // Function: IMLOG10
1430 //
1431 Value func_imlog10(valVector args, ValueCalc *calc, FuncExtra *)
1432 {
1433     return Value(std::log10(calc->conv()->toComplex(args[0])));
1434 }
1435 
1436 
1437 //
1438 // Function: IMEXP
1439 //
1440 Value func_imexp(valVector args, ValueCalc *calc, FuncExtra *)
1441 {
1442     return Value(std::exp(calc->conv()->toComplex(args[0])));
1443 }
1444 
1445 
1446 //
1447 // Function: IMSQRT
1448 //
1449 Value func_imsqrt(valVector args, ValueCalc *calc, FuncExtra *)
1450 {
1451     return Value(std::sqrt(calc->conv()->toComplex(args[0])));
1452 }
1453 
1454 
1455 //
1456 // Function: IMPOWER
1457 //
1458 Value func_impower(valVector args, ValueCalc *calc, FuncExtra *)
1459 {
1460     return Value(std::pow(calc->conv()->toComplex(args[0]),
1461                           calc->conv()->toComplex(args[1])));
1462 }
1463 
1464 
1465 //
1466 // Function: DELTA
1467 //
1468 Value func_delta(valVector args, ValueCalc *calc, FuncExtra *)
1469 {
1470     Value val1 = args[0];
1471     Value val2 = Value(0.0);
1472     if (args.count() == 2)
1473         val2 = args[1];
1474 
1475     return Value(calc->approxEqual(val1, val2) ? 1 : 0);
1476 }
1477 
1478 
1479 //
1480 // Function: ERF
1481 //
1482 Value func_erf(valVector args, ValueCalc *calc, FuncExtra *)
1483 {
1484     if (args.count() == 2)
1485         return calc->sub(calc->erf(args[1]), calc->erf(args[0]));
1486     return calc->erf(args[0]);
1487 }
1488 
1489 
1490 //
1491 // Function: ERFC
1492 //
1493 Value func_erfc(valVector args, ValueCalc *calc, FuncExtra *)
1494 {
1495     if (args.count() == 2)
1496         return calc->sub(calc->erfc(args[1]), calc->erfc(args[0]));
1497     return calc->erfc(args[0]);
1498 }
1499 
1500 
1501 //
1502 // Function: GESTEP
1503 //
1504 Value func_gestep(valVector args, ValueCalc *calc, FuncExtra *)
1505 {
1506     Value x = args[0];
1507     Value y = Value(0.0);
1508     if (args.count() == 2)
1509         y = args[1];
1510 
1511     if (x.isString() || y.isString())
1512         return Value::errorNUM();
1513 
1514     int result = 0;
1515     if (calc->greater(x, y) || calc->approxEqual(x, y))
1516         result = 1;
1517 
1518     return Value(result);
1519 }
1520 
1521 #include "engineering.moc"