| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- //
- // bigdecimal.t.h
- // bigdecimal
- //
- // Created by Sam Jaffe on 7/5/17.
- //
- #pragma once
- #include "bigdecimal.h"
- #include <cxxtest/TestSuite.h>
- class bigdecimal_TestSuite : public CxxTest::TestSuite {
- public:
- // void testConstructFromStringIsSameValueAsFromInt() {
- // using bi = math::bigdecimal;
- // TS_ASSERT_EQUALS(bi("1000000"), bi(1000000));
- // }
- //
-
- void testConstructIntegerAsDecimal() {
- using bd = math::bigdecimal;
- TS_ASSERT_EQUALS(bd("1000.00").to_string(), "1000.00");
- }
- void testConstructDecimal() {
- using bd = math::bigdecimal;
- TS_ASSERT_EQUALS(bd("1000.10").to_string(), "1000.10");
- TS_ASSERT_EQUALS(bd("1000.01").to_string(), "1000.01");
- }
- void testRescaleHigherAddsDigits() {
- math::bigdecimal dec(100);
- TS_ASSERT_EQUALS(dec.scale(), 0);
- dec.rescale(2);
- TS_ASSERT_EQUALS(dec.to_string(), "100.00");
- }
-
- void testRescaleLowerCanBeLossy() {
- math::bigdecimal dec("100.10");
- TS_ASSERT_EQUALS(dec.scale(), 2);
- dec.rescale(0);
- dec.rescale(2);
- TS_ASSERT_EQUALS(dec.to_string(), "100.00");
- }
-
- void testNegativeScaleLosesLowerDigits() {
- math::bigdecimal dec("123", -2);
- TS_ASSERT_EQUALS(dec.to_string(), "100");
- }
-
- void testConstructWithScaleEqualsWithout() {
- math::bigdecimal scl(100, -2);
- TS_ASSERT_EQUALS(scl.to_string(), "100");
- }
-
- void testScaleBelowNegSegDoesntLoseAnything() {
- TS_ASSERT_EQUALS(math::bigdecimal("1000000000", -9).to_string(),
- "1000000000");
- }
-
- void testAddTwoDecimalsSameScale() {
- using bd = math::bigdecimal;
- bd a("1000.10");
- bd b("1000.01");
- TS_ASSERT_EQUALS(a.scale(), b.scale());
- TS_ASSERT_EQUALS((a+b).to_string(), "2000.11");
- }
-
- void testAddTwoDecimalsDifferentScalesUsesHigherScale() {
- using bd = math::bigdecimal;
- bd a("1000.10");
- bd b("1000");
- TS_ASSERT(a.scale() > b.scale());
- TS_ASSERT_EQUALS((a+b).to_string(), "2000.10");
- }
-
- void testAddNumberWithInversePreservesScale() {
- math::bigdecimal a("1.001");
- TS_ASSERT_EQUALS((a+(-a)).to_string(), "0.000");
- }
-
- void testSubtractTwoDecimalsDifferentScalesUsesHigherScale() {
- using bd = math::bigdecimal;
- bd a("900.10");
- bd b("1000");
- TS_ASSERT(a.scale() > b.scale());
- TS_ASSERT_EQUALS((a-b).to_string(), "-99.90");
- TS_ASSERT_EQUALS((b-a).to_string(), "99.90");
- }
- void testMultiplicationIncreasesScale() {
- math::bigdecimal bd("1.1");
- auto out = bd * bd;
- TS_ASSERT_EQUALS(out.scale(), bd.scale() + bd.scale());
- TS_ASSERT_EQUALS(out.to_string(), "1.21");
- }
-
- void testMultiplicationNegativeScaleCountersPositiveScale() {
- math::bigdecimal a("0.01");
- math::bigdecimal b("100", -2);
- TS_ASSERT_EQUALS((a*b).to_string(), "1");
- }
-
- void testMultiplicationCreateNewOffsetCell() {
- math::bigdecimal C(1, 5);
- TS_ASSERT_EQUALS((C*C).to_string(), "1.0000000000");
- }
- void testMultiplicationNegativeToPositiveScale() {
- math::bigdecimal C(1, 5);
- math::bigdecimal D(100, -2);
- TS_ASSERT_EQUALS((D*C).to_string(), "100.000");
- }
-
- void testMultiplicationFromDroppedToNonDropScale() {
- math::bigdecimal C(1, 5);
- math::bigdecimal E(1000000000, -9);
- TS_ASSERT_EQUALS((E*C).to_string(), "1000000000");
- }
- void testMultiplicationFromDroppedToLowerScale() {
- math::bigdecimal D(100, -2);
- math::bigdecimal E(1000000000, -9);
- TS_ASSERT_EQUALS((E*D).to_string(), "100000000000");
- }
- void testMultiplicationFromNonDropToDroppedScale() {
- math::bigdecimal F(10000, -4);
- math::bigdecimal G(100000, -5);
- TS_ASSERT_EQUALS((G*F).to_string(), "1000000000");
- }
-
- math::bigdecimal __create(int32_t scale) {
- if (scale >= 0) return { "1", scale };
- std::vector<char> data(size_t(std::abs(scale))+3, 0);
- data[0] = '1';
- sprintf(data.data()+1, "%0.*d", -scale, 0);
- return { data.data(), scale };
- }
-
- std::string __createExpect(int32_t scale1, int32_t scale2) {
- int32_t decimals{0}, magnitude{std::min(scale1, scale2)};
- if (scale1 < 0 == scale2 < 0) {
- decimals = scale1 + scale2;
- } else if (scale1 > 0 && scale1 > -scale2) {
- decimals = scale1 + scale2;
- } else if (scale2 > 0 && scale2 > -scale1) {
- decimals = scale1 + scale2;
- } else {
- decimals = std::min(scale1, scale2);
- }
- if (decimals < 0) { magnitude = decimals; }
- std::vector<char> data(size_t(std::abs(decimals) + std::abs(magnitude))+4, 0);
- char * ptr = data.data();
- *ptr++ = '1';
- if (magnitude < 0) {
- ptr += sprintf(ptr, "%0.*d", -magnitude, 0);
- }
- if (decimals > 0) {
- sprintf(ptr, ".%0.*d", decimals, 0);
- }
- return data.data();
- }
-
- void __testMultiplyScales(int32_t scale1, int32_t scale2) {
- math::bigdecimal A(__create(scale1));
- math::bigdecimal B(__create(scale2));
- // This is wrong
- std::string expected(__createExpect(scale1, scale2));
- TS_ASSERT_EQUALS((A*B).to_string(), expected);
- TS_ASSERT_EQUALS((B*A).to_string(), expected);
- }
-
- void testMultiplicationBrutePermutations() {
- for (int32_t i = -20; i <= +20; ++i) {
- for (int32_t j = i; j <= +20; ++j) {
- __testMultiplyScales(i, j);
- }
- }
- }
- void testDivideHigherScaleByLowerScale() {
- math::bigdecimal a("1", 2);
- math::bigdecimal b("1", 1);
- TS_ASSERT_EQUALS((a/b).to_string(), "1.0");
- }
- void testDivideLowerScaleByHigherScale() {
- math::bigdecimal a("10", 1);
- math::bigdecimal b("1", 2);
- TS_ASSERT_EQUALS((a/b).to_string(), "10");
- }
- };
|