////////////////////////////////////////////////////////////////////// // tadv/CalcBasic.cpp: basic calculator operations. #include "TCoreCalc.h" #pragma hdrstop #pragma BLITZ_APPROVE #include "CalcBasic.h" #ifdef PLATFORM_WIN32 #include #endif #ifdef PLATFORM_POSIX #include #endif #ifdef PLATFORM_SOLARIS #include #endif namespace Upp { void UseCalcBasic() {} // to bring in globally constructed objects String PluralFormat(int i, const char *b) { if(IsNull(i)) return Null; String out; out << NlsFormat(i) << ' '; i = tabs(i) % 100; if(i < 10 || i > 20) i %= 10; const char *p = b; while(*p && *p != '/') p++; if(p > b) out.Cat(b, p - b); if(*p) p++; b = p; while(*p && *p != '/') p++; if(i == 1) { out.Cat(b, p - b); return out; } if(*p) p++; b = p; while(*p && *p != '/') p++; if(i >= 2 && i <= 4) { out.Cat(b, p - b); return out; } if(*p) p++; out.Cat(p); return out; } String GroupComp() { return t_("Comparison"); } String GroupBitOp() { return t_("Bit field operations"); } String GroupArith() { return t_("Arithmetical operations"); } String GroupLog() { return t_("Logical operations"); } String GroupString() { return t_("Text operations"); } String GroupDate() { return t_("Date operations"); } String GroupArray() { return t_("Array functions"); } String GroupConst() { return t_("Constants"); } String GroupTrans() { return t_("Transcendental functions"); } String GroupSystem() { return t_("System functions"); } ////////////////////////////////////////////////////////////////////// // equality / inequality inline bool CeqVV(Value a, Value b) { return a == b; } inline bool CneVV(Value a, Value b) { return a != b; } FDECL("==", CeqVV, &GroupComp) FDECL("!=", CneVV, &GroupComp) inline bool CltNN(double a, double b) { return a < b; } inline bool CleNN(double a, double b) { return a <= b; } inline bool CgtNN(double a, double b) { return a > b; } inline bool CgeNN(double a, double b) { return a >= b; } FDECL("<", CltNN, &GroupComp) FDECL("<=", CleNN, &GroupComp) FDECL(">", CgtNN, &GroupComp) FDECL(">=", CgeNN, &GroupComp) inline bool CltTT(Time a, Time b) { return a < b; } inline bool CleTT(Time a, Time b) { return a <= b; } inline bool CgtTT(Time a, Time b) { return a > b; } inline bool CgeTT(Time a, Time b) { return a >= b; } FDECL("<", CltTT, &GroupComp) FDECL("<=", CleTT, &GroupComp) FDECL(">", CgtTT, &GroupComp) FDECL(">=", CgeTT, &GroupComp) inline bool CltSS(CalcPacket& packet, WString a, WString b) { return GetLanguageInfo(packet.context.language).Compare(a, b) < 0; } inline bool CleSS(CalcPacket& packet, WString a, WString b) { return GetLanguageInfo(packet.context.language).Compare(a, b) <= 0; } inline bool CgtSS(CalcPacket& packet, WString a, WString b) { return GetLanguageInfo(packet.context.language).Compare(a, b) > 0; } inline bool CgeSS(CalcPacket& packet, WString a, WString b) { return GetLanguageInfo(packet.context.language).Compare(a, b) >= 0; } FDECLA("<", CltSS, &GroupString) FDECLA("<=", CleSS, &GroupString) FDECLA(">", CgtSS, &GroupString) FDECLA(">=", CgeSS, &GroupString) ////////////////////////////////////////////////////////////////////// // bit-op's inline int CbitAndNN(int a, int b) { return a & b; } inline int CbitOrNN(int a, int b) { return a | b; } inline int CbitXorNN(int a, int b) { return a ^ b; } FDECL0("&", CbitAndNN, &GroupBitOp) FDECL0("|", CbitOrNN, &GroupBitOp) FDECL0("^", CbitXorNN, &GroupBitOp) ////////////////////////////////////////////////////////////////////// // unaries inline double CplusN(double value) { return +value; } inline double CminusN(double value) { return -value; } inline int CbitNotN(int value) { return ~value; } inline bool ClogNotN(double value) { return value ? 0 : 1; } inline bool ClogNotS(WString s) { return s.IsEmpty(); } FDECL0("+", CplusN, &GroupArith) FDECL0("-", CminusN, &GroupArith) FDECL0("~", CbitNotN, &GroupBitOp) FDECL("!", ClogNotS, &GroupLog) FDECL("!", ClogNotN, &GroupLog) ////////////////////////////////////////////////////////////////////// // additives inline double CaddNN(double a, double b) { return a + b; } FDECL0("+", CaddNN, &GroupArith) inline WString CaddSS(WString a, WString b) { return a + b; } FDECL ("+", CaddSS, &GroupString) inline Time CaddDN(Time a, double b) { return a + fround64(b * 86400.0 + 0.5); } FDECL0("+", CaddDN, &GroupDate) inline Time CaddND(double a, Time b) { return b + fround64(a * 86400.0 + 0.5); } FDECL0("+", CaddND, &GroupDate) inline double CsubNN(double a, double b) { return a - b; } inline Time CsubDN(Time a, double b) { return a - fround64(b * 86400.0); } inline double CsubDD(Time a, Time b) { return (a - b) / 86400.0; } FDECL0("-", CsubNN, &GroupArith) FDECL0("-", CsubDN, &GroupDate) FDECL0("-", CsubDD, &GroupDate) ////////////////////////////////////////////////////////////////////// // shifts inline int CsalNN(int a, int b) { return a << b; } inline int CsarNN(int a, int b) { return a >> b; } FDECL0("<<", CsalNN, &GroupBitOp) FDECL0(">>", CsarNN, &GroupBitOp) ////////////////////////////////////////////////////////////////////// // multiplicatives inline double CmulNN(double a, double b) { return a * b; } inline WString CmulSN(WString s, int i) { if(i <= 0 || IsNull(s)) return Null; if(i == 1) return s; int len = s.GetLength() * i; WStringBuffer result(len); memsetex(result, s, sizeof(wchar) * s.GetLength(), i); return result; } inline WString CmulNS(int i, WString s) { return CmulSN(s, i); } FDECL0("*", CmulNN, &GroupArith) FDECL0("*", CmulSN, &GroupString) FDECL0("*", CmulNS, &GroupString) inline double CdivNN(double a, double b) { if(!b) throw Exc(t_("division by zero")); return a / b; } FDECL0("/", CdivNN, &GroupArith) inline double CmodNN(double a, double b) { if(!b) throw Exc(t_("division by zero")); return fmod(a, b); } FDECL0("%", CmodNN, &GroupArith) ////////////////////////////////////////////////////////////////////// // rounding static void ChkDigits(int c) { if(c < -20 || c >= 20) throw Exc(NFormat(t_("invalid number of places (%d)"), c)); } inline double GetTimes(int c) { ChkDigits(c); return ipow10(c); } inline double CroundN(double a) { return floor(a + 0.5); } inline double CroundNN(double a, int c) { double t = GetTimes(c); return floor(a * t + 0.5) / t; } inline double CroundrNN(double a, int c) { ChkDigits(c); return roundr(a, c); } FDECLP0(round, N, &GroupArith) FDECLP0(round, NN, &GroupArith) FDECLP0(roundr, NN, &GroupArith) inline double CfloorN(double a) { return floor(a); } inline double CfloorNN(double a, int c) { double t = GetTimes(c); return floor(a * t) / t; } inline double CfloorrNN(double a, int c) { ChkDigits(c); return floorr(a, c); } FDECLP0(floor, N, &GroupArith) FDECLP0(floor, NN, &GroupArith) FDECLP0(floorr, NN, &GroupArith) inline double CceilN(double a) { return ceil(a); } inline double CceilNN(double a, int c) { double t = GetTimes(c); return ceil(a * t) / t; } inline double CceilrNN(double a, int c) { ChkDigits(c); return ceilr(a, c); } FDECLP0(ceil, N, &GroupArith) FDECLP0(ceil, NN, &GroupArith) FDECLP0(ceilr, NN, &GroupArith) inline double CminNN(double a, double b) { return min(a, b); } inline double CmaxNN(double a, double b) { return max(a, b); } inline double CminmaxNNN(double a, double l, double h) { return minmax(a, l, h); } FDECLP(min, NN, &GroupComp) FDECLP(max, NN, &GroupComp) FDECLP(minmax, NNN, &GroupComp) inline Time CminTT(Time a, Time b) { return min(a, b); } inline Time CmaxTT(Time a, Time b) { return max(a, b); } inline Time CminmaxTTT(Time a, Time l, Time h) { return minmax(a, l, h); } FDECLP(min, TT, &GroupComp) FDECLP(max, TT, &GroupComp) FDECLP(minmax, TTT, &GroupComp) inline WString CminSS(CalcPacket& packet, WString a, WString b) { return GetLanguageInfo(packet.context.language).Compare(a, b) <= 0 ? a : b; } inline WString CmaxSS(CalcPacket& packet, WString a, WString b) { return GetLanguageInfo(packet.context.language).Compare(a, b) >= 0 ? a : b; } inline WString CminmaxSSS(CalcPacket& packet, WString a, WString l, WString h) { return CminSS(packet, CmaxSS(packet, a, l), h); } FDECLAP(min, SS, &GroupComp) FDECLAP(max, SS, &GroupComp) FDECLAP(minmax, SSS, &GroupComp) inline double Ce0() { return M_E; } inline double Cpi0() { return M_PI; } FDECLP(e, 0, &GroupConst) FDECLP(pi, 0, &GroupConst) inline double CabsN(double x) { return fabs(x); } FDECLP(abs, N, &GroupArith) inline int CsgnN(double x) { return sgn(x); } FDECLP(sgn, N, &GroupArith) inline int CascS(WString s) { return (byte)*s; } inline WString CchrN(int c) { return WString(c, 1); } inline int ClenS(WString s) { return s.GetLength(); } FDECLP(asc, S, &GroupString) FDECLP(chr, N, &GroupString) FDECLP(len, S, &GroupString) inline String CcountNS(int i, WString s) { return PluralFormat(i, s.ToString()); } FDECLP(count, NS, &GroupString) inline String CnlsN(double d) { return NlsFormat(d, 3); } inline String CnlsNN(double d, int places) { return NlsFormat(d, places); } inline String CnlsrN(double d) { return NlsFormatRel(d, 3); } inline String CnlsrNN(double d, int places) { return NlsFormatRel(d, places); } FDECLP0(nls, N, &GroupString) FDECLP0(nls, NN, &GroupString) FDECLP0(nlsr, N, &GroupString) FDECLP0(nlsr, NN, &GroupString) inline String CtextN(double d) { return FormatDouble(d, 10); } inline String CitextN(int i) { return FormatInt(i); } inline String CitextNN(int i, int p) { return FormatIntDec(i, p, ' '); } inline String Citext0NN(int i, int p) { return FormatIntDec(i, p, '0'); } inline String CftextN(double d) { return AsString(d, 0); } inline String CftextNI(double d, int places) { return AsString(d, places); } FDECLP(text, N, &GroupString) FDECLP0(itext, N, &GroupString) FDECLP0(itext, NN, &GroupString) FDECLP0(itext0, NN, &GroupString) FDECLP0(ftext, N, &GroupString) FDECLP0(ftext, NI, &GroupString) inline WString CtextS(WString s) { return s; } inline String CtextD(CalcPacket& packet, Time d) { return GetLanguageInfo(packet.context.language).FormatDate(d); } FDECLP(text, S, &GroupString) FDECLAP(text, D, &GroupString) inline String CtextA(CalcPacket& packet, const ValueArray& va) { String out; out << "["; for(int i = 0; i < va.GetCount(); i++) out << (i ? ", " : "") << packet.context.FormatText(va[i]); out << "]"; return out; } FDECLAP(text, A, &GroupString) inline WString CleftSN(WString s, int n) { return s.Left(minmax(n, 0, s.GetLength())); } inline WString CrightSN(WString s, int n) { return s.Right(minmax(n, 0, s.GetLength())); } inline WString CmidSNN(WString s, int m, int n) { m = minmax(m, 0, s.GetLength()); n = minmax(n, 0, s.GetLength() - m); return s.Mid(m, n); } inline WString CmidSN(WString s, int m) { return CmidSNN(s, m, max(0, s.GetLength() - m)); } FDECLP(left, SN, &GroupString) FDECLP(right, SN, &GroupString) FDECLP(mid, SN, &GroupString) FDECLP(mid, SNN, &GroupString) inline WString CcatSSS(WString a, WString b, WString c) { if(IsNull(c)) return a; if(IsNull(a)) return c; return a + b + c; } FDECLP(cat, SSS, &GroupString) inline WString ClpadSNS(WString a, int len, WString b) { int al = a.GetLength(), bl = b.GetLength(), add = len - al; if(bl == 0 || add <= 0) return a; WString out; if(bl == 1) out.Cat(*b, add); else { while(add >= bl) { out.Cat(b); add -= bl; } if(add > 0) out.Cat(b, add); } out.Cat(a); return out; } FDECLP(lpad, SNS, &GroupString) inline WString ClpadSN(WString a, int len) { return ClpadSNS(a, len, WString(' ', 1)); } FDECLP(lpad, SN, &GroupString) WString CllpadSNS(WString a, int len, WString b) { if(a.GetLength() > len) return a.Right(len); return ClpadSNS(a, len, b); } FDECLP(llpad, SNS, &GroupString) inline WString CllpadSN(WString a, int len) { return CllpadSNS(a, len, WString(' ', 1)); } FDECLP(llpad, SN, &GroupString) inline WString CrpadSNS(WString a, int len, WString b) { int al = a.GetLength(), bl = b.GetLength(), add = len - al; if(bl == 0 || add <= 0) return a; if(bl == 1) a.Cat(*b, add); else { while(add >= bl) { a.Cat(b); add -= bl; } if(add > 0) a.Cat(b, add); } return a; } FDECLP(rpad, SNS, &GroupString) inline WString CrpadSN(WString a, int len) { return CrpadSNS(a, len, WString(' ', 1)); } FDECLP(rpad, SN, &GroupString) inline WString CrrpadSNS(WString a, int len, WString b) { if(a.GetLength() > len) { a.Trim(len); return a; } return CrpadSNS(a, len, b); } FDECLP(rrpad, SNS, &GroupString) inline WString CrrpadSN(WString a, int len) { return CrrpadSNS(a, len, WString(' ', 1)); } FDECLP(rrpad, SN, &GroupString) inline double CnumberS(String s) { const char *p = s; double d = ScanDouble(p, &p); if(IsNull(d) || *p) throw Exc(NFormat(t_("invalid numeric format: '%s'"), s)); return d; } inline double CnumberSN(String s, double dflt) { const char *p = s; double d = ScanDouble(p, &p); #ifdef PLATFORM_WIN32 return (IsNull(d) || !_finite(d) || _isnan(d) || *p ? dflt : d); #elif defined(PLATFORM_POSIX) return (IsNull(d) || !finite(d) || *p ? dflt : d); // PLATFORM_SOLARIS // return (IsNull(d) || isinf(d) || isnan(d) || *p ? dflt : d); #else #error #endif } FDECLP(number, S, &GroupString) FDECLP(number, SN, &GroupString) inline bool IsValidYear(int year) { return year >= -4000 && year <= +4000; } inline Date CdateNNN(int day, int month, int year) { if(!IsValidYear(year)) throw Exc(NFormat(t_("invalid year number (%d)"), year)); if(month <= 0 || month > 12) throw Exc(NFormat(t_("invalid month number (%d)"), month)); Date date(year, month, 1); if(day <= 0 || day > LastDayOfMonth(date).day) throw Exc(NFormat(t_("invalid day number (%d)"), day)); date.day = day; return date; } inline Date CdateNN(int day, int month) { return CdateNNN(day, month, GetSysDate().year); } inline Date CdateN(int day) { Date date = GetSysDate(); return CdateNNN(day, date.month, date.year); } inline Date Cdate0() { return GetSysDate(); } FDECLP0(date, 0, &GroupDate) FDECLP0(date, N, &GroupDate) FDECLP0(date, NN, &GroupDate) FDECLP0(date, NNN, &GroupDate) inline Date CdateSD(CalcPacket& packet, String s, Date dflt) { Date out; const char *p = StrToDate(out, s); return p ? out : dflt; } inline Date CdateS(CalcPacket& packet, String s) { return CdateSD(packet, s, Null); } inline Date CdateT(Time t) { return t; } FDECLAP(date, S, &GroupDate) FDECLAP(date, SD, &GroupDate) FDECLP(date, T, &GroupDate) inline Time Ctime0() { return GetSysTime(); } FDECLP0(time, 0, &GroupDate) bool CtimeNNNNNN(CalcPacket& packet) { if(packet.help) { packet.args.SetCount(6, CalcType::Describe()); packet.result = CalcType