context: /*
  Copyright 2014 Alex Dyachenko
  
  This file is part of the MPIR Library.
  
  The MPIR Library is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License as published
  by the Free Software Foundation; either version 3 of the License, or (at
  your option) any later version.
  
  The MPIR Library is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  License for more details.
  
  You should have received a copy of the GNU Lesser General Public License
  along with the MPIR Library.  If not, see http://www.gnu.org/licenses/.  
  */
  
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  
  namespace MPIR.Tests.HugeFloatTests
  {
      public static class FloatAssert
      {
          public static void AreEqual(string expected, HugeFloat actual)
          {
              var actualStr = actual.ToString();
              if(expected[0] == '-')
              {
                  Assert.AreEqual(expected[0], actualStr[0]);
                  actualStr = actualStr.TrimStart('-');
                  expected = expected.TrimStart('-');
              }
  
              var exponent = expected.IndexOf('.');
              if(exponent < 0) exponent = expected.Length;
              expected = expected.Replace(".", "");
  
              var exponentStr = "@" + exponent;
  
              Assert.IsTrue(actualStr.StartsWith("0."));
              actualStr = actualStr.Substring(2);
  
              Assert.IsTrue(actualStr.EndsWith(exponentStr));
              actualStr = actualStr.Substring(0, actualStr.Length - exponentStr.Length);
  
              if (expected.Length > actualStr.Length)
              {
                  var roundedUp = expected[actualStr.Length] >= '5';
                  expected = expected.Substring(0, actualStr.Length);
                  if(roundedUp)
                  {
                      using (var a = new HugeInt(expected))
                      {
                          a.Value += 1;
                          expected = a.ToString(10);
                      }
                  }
              }
              Assert.AreEqual(expected, actualStr);
          }
      }
  
      [TestClass]
      public class Arithmetic
      {
          [ClassInitialize]
          public static void Setup(TestContext context)
          {
              HugeFloat.DefaultPrecision = 128;
          }
  
          [ClassCleanup]
          public static void Cleanup()
          {
              HugeFloat.DefaultPrecision = 64;
          }
  
          #region Add
  
          [TestMethod]
          public void FloatAddHugeFloat()
          {
              using (var a = new HugeFloat("22250983250345029834502983.5740293845720"))
              using (var b = new HugeFloat("2229874359879827.30594288574029879874539"))
              using (var c = new HugeFloat(a + b))
              {
                  FloatAssert.AreEqual("22250983252574904194382810.87997227031229879874539", c);
                  c.Value = a + (b + 1);
                  FloatAssert.AreEqual("22250983252574904194382811.87997227031229879874539", c);
              }
          }
  
          [TestMethod]
          public void FloatAddLimb()
          {
              using (var a = new HugeFloat("22250983250345029834502983.5740293845720"))
              using (var c = new HugeFloat())
              {
                  var b = Platform.Ui(4288574029879874539UL, 4288574029U);
                  var expected = Platform.Select("22250987538919059714377522.5740293845720", "22250983250345034123077012.5740293845720");
                  c.Value = a + b;
                  FloatAssert.AreEqual(expected, c);
                  c.Value = b + a;
                  FloatAssert.AreEqual(expected, c);
              }
          }
  
          [TestMethod]
          public void FloatAddSignedLimb()
          {
              using (var a = new HugeFloat("22250983250345029834502983.5740293845720"))
              using (var c = new HugeFloat())
              {
                  var b = Platform.Si(-4288574029879874539, -1288574029);
                  var expected = Platform.Select("22250978961770999954628444.5740293845720", "22250983250345028545928954.5740293845720");
                  c.Value = a + b;
                  FloatAssert.AreEqual(expected, c);
                  c.Value = b + a;
                  FloatAssert.AreEqual(expected, c);
              }
          }
  
          #endregion
  
          #region Subtract
  
          [TestMethod]
          public void FloatSubtractHugeFloat()
          {
              using (var a = new HugeFloat("22250983250345029834502983.5740293845720"))
              using (var b = new HugeFloat("2229874359879827.30594288574029879874539"))
              using (var c = new HugeFloat(a - b))
              {
                  FloatAssert.AreEqual("22250983248115155474623156.26808649883170120125461", c);
                  c.Value = b - (a + 1);
                  FloatAssert.AreEqual("-22250983248115155474623157.26808649883170120125461", c);
              }
          }
  
          [TestMethod]
          public void FloatSubtractLimb()
          {
              using(var a = new HugeFloat("22250983250345029834502983.5740293845720"))
              using(var c = new HugeFloat())
              {
                  var b = Platform.Ui(4288574029879874539UL, 2885740298U);
                  var expected = Platform.Select("22250978961770999954628444.5740293845720", "22250983250345026948762685.5740293845720");
                  c.Value = a - b;
                  FloatAssert.AreEqual(expected, c);
                  c.Value = b - a;
                  FloatAssert.AreEqual("-" + expected, c);
              }
          }
  
          [TestMethod]
          public void FloatSubtractSignedLimb()
          {
              using(var a = new HugeFloat("22250983250345029834502983.5740293845720"))
              using(var c = new HugeFloat())
              {
                  var b = Platform.Si(-4288574029879874539, -1885740298);
                  var expected = Platform.Select("22250987538919059714377522.5740293845720", "22250983250345031720243281.5740293845720");
                  c.Value = a - b;
                  FloatAssert.AreEqual(expected, c);
                  c.Value = b - a;
                  FloatAssert.AreEqual("-" + expected, c);
              }
          }
  
          #endregion
  
          #region Multiply
  
          [TestMethod]
          public void FloatMultiplyByHugeFloat()
          {
              using (var a = new HugeFloat("90234098723098475098479385.345098345"))
              using (var b = new HugeFloat("78594873598734.59872354987610987897"))
              using (var c = new HugeFloat(a * b))
              {
                  FloatAssert.AreEqual("7091937583437663707014199538801620613535.95657143399816050772069730465", c);
                  c.Value = b * (a + 1);
                  FloatAssert.AreEqual("7091937583437663707014199617396494212270.55529498387427038669069730465", c);
              }
          }
  
          [TestMethod]
          public void FloatMultiplyByLimb()
          {
              using (var a = new HugeFloat("9023409872309847509847.9385345098345"))
              using (var c = new HugeFloat())
              {
                  var b = Platform.Ui(17390538260286101342, 1500450271);
                  var expected = Platform.Select("156921954622647727368660197878904460649174.746962647899", "13539177788251386092120014542896.6240276901495");
                  c.Value = a * b;
                  FloatAssert.AreEqual(expected, c);
                  c.Value = b * -a;
                  FloatAssert.AreEqual("-" + expected, c);
              }
          }
  
          [TestMethod]
          public void FloatMultiplyBySignedLimb()
          {
              using (var a = new HugeFloat("9023409872309847509847.9385345098345"))
              using (var c = new HugeFloat())
              {
                  var b = Platform.Si(-7390538260286101342, -1500450271);
                  var expected = Platform.Select("66687855899549252270180812533806115649174.746962647899", "13539177788251386092120014542896.6240276901495");
                  c.Value = a * b;
                  FloatAssert.AreEqual("-" + expected, c);
  
gt:                 c.Value = b * -a;