// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. library math_test; import "package:expect/expect.dart"; import 'dart:math'; class MathTest { static void testConstants() { // Source for mathematical constants is Wolfram Alpha. Expect.equals( 2.7182818284590452353602874713526624977572470936999595749669, e, ); Expect.equals( 2.3025850929940456840179914546843642076011014886287729760333, ln10, ); Expect.equals( 0.6931471805599453094172321214581765680755001343602552541206, ln2, ); Expect.equals( 1.4426950408889634073599246810018921374266459541529859341354, log2e, ); Expect.equals( 0.4342944819032518276511289189166050822943970058036665661144, log10e, ); Expect.equals( 3.1415926535897932384626433832795028841971693993751058209749, pi, ); Expect.equals( 0.7071067811865475244008443621048490392848359376884740365883, sqrt1_2, ); Expect.equals( 1.4142135623730950488016887242096980785696718753769480731766, sqrt2, ); } static checkClose(double a, double b, EPSILON) { Expect.equals(true, a - EPSILON <= b); Expect.equals(true, b <= a + EPSILON); } static void testSin() { // Given the imprecision of pi we can't expect better results than this. final double EPSILON = 1e-15; checkClose(0.0, sin(0.0), EPSILON); checkClose(0.0, sin(pi), EPSILON); checkClose(0.0, sin(2.0 * pi), EPSILON); checkClose(1.0, sin(pi / 2.0), EPSILON); checkClose(-1.0, sin(pi * (3.0 / 2.0)), EPSILON); } static void testCos() { // Given the imprecision of pi we can't expect better results than this. final double EPSILON = 1e-15; checkClose(1.0, cos(0.0), EPSILON); checkClose(-1.0, cos(pi), EPSILON); checkClose(1.0, cos(2.0 * pi), EPSILON); checkClose(0.0, cos(pi / 2.0), EPSILON); checkClose(0.0, cos(pi * (3.0 / 2.0)), EPSILON); } static void testTan() { // Given the imprecision of pi we can't expect better results than this. final double EPSILON = 1e-15; checkClose(0.0, tan(0.0), EPSILON); checkClose(0.0, tan(pi), EPSILON); checkClose(0.0, tan(2.0 * pi), EPSILON); checkClose(1.0, tan(pi / 4.0), EPSILON); } static void testAsin() { // Given the imprecision of pi we can't expect better results than this. final double EPSILON = 1e-15; checkClose(0.0, asin(0.0), EPSILON); checkClose(pi / 2.0, asin(1.0), EPSILON); checkClose(-pi / 2.0, asin(-1.0), EPSILON); } static void testAcos() { // Given the imprecision of pi we can't expect better results than this. final double EPSILON = 1e-15; checkClose(0.0, acos(1.0), EPSILON); checkClose(pi, acos(-1.0), EPSILON); checkClose(pi / 2.0, acos(0.0), EPSILON); } static void testAtan() { // Given the imprecision of pi we can't expect better results than this. final double EPSILON = 1e-15; checkClose(0.0, atan(0.0), EPSILON); checkClose(pi / 4.0, atan(1.0), EPSILON); checkClose(-pi / 4.0, atan(-1.0), EPSILON); } static void testAtan2() { // Given the imprecision of pi we can't expect better results than this. final double EPSILON = 1e-15; checkClose(0.0, atan2(0.0, 5.0), EPSILON); checkClose(pi / 4.0, atan2(2.0, 2.0), EPSILON); checkClose(3 * pi / 4.0, atan2(0.5, -0.5), EPSILON); checkClose(-3 * pi / 4.0, atan2(-2.5, -2.5), EPSILON); } static checkVeryClose(double a, double b) { // We find a ulp (unit in the last place) by shifting the original number // to the right. This only works if we are not too close to infinity or if // we work with denormals. // We special case or 0.0, but not for infinity. if (a == 0.0) { final minimalDouble = 4.9406564584124654e-324; Expect.equals(true, b.abs() <= minimalDouble); return; } if (b == 0.0) { // No need to look if they are close. Otherwise the check for 'a' above // would have triggered. Expect.equals(a, b); } final double shiftRightBy52 = 2.220446049250313080847263336181640625e-16; final double shiftedA = (a * shiftRightBy52).abs(); // Compared to 'a', 'shiftedA' is now ~1-2 ulp. final double limitLow = a - shiftedA; final double limitHigh = a + shiftedA; Expect.equals(false, a == limitLow); Expect.equals(false, a == limitHigh); Expect.equals(true, limitLow <= b); Expect.equals(true, b <= limitHigh); } static void testSqrt() { checkVeryClose(2.0, sqrt(4.0)); checkVeryClose(sqrt2, sqrt(2.0)); checkVeryClose(sqrt1_2, sqrt(0.5)); checkVeryClose(1e50, sqrt(1e100)); checkVeryClose( 1.1111111061110855443054405046358901279277111935183977e56, sqrt(12345678901234e99), ); } static void testExp() { checkVeryClose(e, exp(1.0)); final EPSILON = 1e-15; checkClose(10.0, exp(ln10), EPSILON); checkClose(2.0, exp(ln2), EPSILON); } static void testLog() { // Even though E is imprecise, it is good enough to get really close to 1. // We still provide an epsilon. checkClose(1.0, log(e), 1e-16); checkVeryClose(ln10, log(10.0)); checkVeryClose(ln2, log(2.0)); } static bool parseIntThrowsFormatException(str) { try { int.parse(str); return false; } on FormatException catch (e) { return true; } } static void testParseInt() { Expect.equals(499, int.parse("499")); Expect.equals(499, int.parse("+499")); Expect.equals(-499, int.parse("-499")); Expect.equals(499, int.parse(" 499 ")); Expect.equals(499, int.parse(" +499 ")); Expect.equals(-499, int.parse(" -499 ")); Expect.equals(0, int.parse("0")); Expect.equals(0, int.parse("+0")); Expect.equals(0, int.parse("-0")); Expect.equals(0, int.parse(" 0 ")); Expect.equals(0, int.parse(" +0 ")); Expect.equals(0, int.parse(" -0 ")); Expect.equals(0x1234567890, int.parse("0x1234567890")); Expect.equals(-0x1234567890, int.parse("-0x1234567890")); Expect.equals(0x1234567890, int.parse(" 0x1234567890 ")); Expect.equals(-0x1234567890, int.parse(" -0x1234567890 ")); Expect.equals(256, int.parse("0x100")); Expect.equals(-256, int.parse("-0x100")); Expect.equals(256, int.parse(" 0x100 ")); Expect.equals(-256, int.parse(" -0x100 ")); Expect.equals(0xabcdef, int.parse("0xabcdef")); Expect.equals(0xABCDEF, int.parse("0xABCDEF")); Expect.equals(0xabcdef, int.parse("0xabCDEf")); Expect.equals(-0xabcdef, int.parse("-0xabcdef")); Expect.equals(-0xABCDEF, int.parse("-0xABCDEF")); Expect.equals(0xabcdef, int.parse(" 0xabcdef ")); Expect.equals(0xABCDEF, int.parse(" 0xABCDEF ")); Expect.equals(-0xabcdef, int.parse(" -0xabcdef ")); Expect.equals(-0xABCDEF, int.parse(" -0xABCDEF ")); Expect.equals(0xabcdef, int.parse("0x00000abcdef")); Expect.equals(0xABCDEF, int.parse("0x00000ABCDEF")); Expect.equals(-0xabcdef, int.parse("-0x00000abcdef")); Expect.equals(-0xABCDEF, int.parse("-0x00000ABCDEF")); Expect.equals(0xabcdef, int.parse(" 0x00000abcdef ")); Expect.equals(0xABCDEF, int.parse(" 0x00000ABCDEF ")); Expect.equals(-0xabcdef, int.parse(" -0x00000abcdef ")); Expect.equals(-0xABCDEF, int.parse(" -0x00000ABCDEF ")); Expect.equals(10, int.parse("010")); Expect.equals(-10, int.parse("-010")); Expect.equals(10, int.parse(" 010 ")); Expect.equals(-10, int.parse(" -010 ")); Expect.equals(9, int.parse("09")); Expect.equals(9, int.parse(" 09 ")); Expect.equals(-9, int.parse("-09")); Expect.equals(0x1234567890, int.parse("+0x1234567890")); Expect.equals(0x1234567890, int.parse(" +0x1234567890 ")); Expect.equals(0x100, int.parse("+0x100")); Expect.equals(0x100, int.parse(" +0x100 ")); Expect.equals(true, parseIntThrowsFormatException("1b")); Expect.equals(true, parseIntThrowsFormatException(" 1b ")); Expect.equals(true, parseIntThrowsFormatException(" 1 b ")); Expect.equals(true, parseIntThrowsFormatException("1e2")); Expect.equals(true, parseIntThrowsFormatException(" 1e2 ")); Expect.equals(true, parseIntThrowsFormatException("00x12")); Expect.equals(true, parseIntThrowsFormatException(" 00x12 ")); Expect.equals(true, parseIntThrowsFormatException("-1b")); Expect.equals(true, parseIntThrowsFormatException(" -1b ")); Expect.equals(true, parseIntThrowsFormatException(" -1 b ")); Expect.equals(true, parseIntThrowsFormatException("-1e2")); Expect.equals(true, parseIntThrowsFormatException(" -1e2 ")); Expect.equals(true, parseIntThrowsFormatException("-00x12")); Expect.equals(true, parseIntThrowsFormatException(" -00x12 ")); Expect.equals(true, parseIntThrowsFormatException(" -00x12 ")); Expect.equals(true, parseIntThrowsFormatException("0x0x12")); Expect.equals(true, parseIntThrowsFormatException("0.1")); Expect.equals(true, parseIntThrowsFormatException("0x3.1")); Expect.equals(true, parseIntThrowsFormatException("5.")); Expect.equals(true, parseIntThrowsFormatException("+-5")); Expect.equals(true, parseIntThrowsFormatException("-+5")); Expect.equals(true, parseIntThrowsFormatException("--5")); Expect.equals(true, parseIntThrowsFormatException("++5")); Expect.equals(true, parseIntThrowsFormatException("+ 5")); Expect.equals(true, parseIntThrowsFormatException("- 5")); Expect.equals(true, parseIntThrowsFormatException("")); Expect.equals(true, parseIntThrowsFormatException(" ")); } static testMain() { testConstants(); testSin(); testCos(); testTan(); testAsin(); testAcos(); testAtan(); testAtan2(); testSqrt(); testLog(); testExp(); testParseInt(); } } main() { MathTest.testMain(); }