From 97dc4edb4569225f4b819717a2fabf0209d312e0 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 8 Mar 2015 20:09:13 +0700 Subject: natspec for poc-9 - put natspec.js in a heredoc string (to help binary) - constructor takes no args, just sets up js vm - API: only exports Notice(transaction, abi, method, expression string) (string, error) - effort to turn natspec.js error strings to proper go errors - test errors --- ethutil/natspec/natspec.go | 58 +- ethutil/natspec/natspec.js | 3517 -------------------------------------- ethutil/natspec/natspec_js.go | 3520 +++++++++++++++++++++++++++++++++++++++ ethutil/natspec/natspec_test.go | 103 +- 4 files changed, 3622 insertions(+), 3576 deletions(-) delete mode 100644 ethutil/natspec/natspec.js create mode 100644 ethutil/natspec/natspec_js.go (limited to 'ethutil') diff --git a/ethutil/natspec/natspec.go b/ethutil/natspec/natspec.go index 00e6f8720..ebc2658da 100644 --- a/ethutil/natspec/natspec.go +++ b/ethutil/natspec/natspec.go @@ -1,24 +1,21 @@ package natspec import ( + "fmt" "github.com/obscuren/otto" - "io/ioutil" ) type NatSpec struct { jsvm *otto.Otto } -func NewNATSpec(transaction string) (self *NatSpec, err error) { +// TODO: should initialise with abi and userdoc jsons +func NewNATSpec() (self *NatSpec, err error) { self = new(NatSpec) self.jsvm = otto.New() - code, err := ioutil.ReadFile("natspec.js") - if err != nil { - return - } - _, err = self.jsvm.Run(string(code)) + _, err = self.jsvm.Run(natspecJS) if err != nil { return } @@ -27,39 +24,40 @@ func NewNATSpec(transaction string) (self *NatSpec, err error) { return } - self.jsvm.Run("var transaction = " + transaction + ";") - - return -} - -func (self *NatSpec) SetDescription(desc string) (err error) { - - _, err = self.jsvm.Run("var expression = \"" + desc + "\";") return - } -func (self *NatSpec) SetABI(abi string) (err error) { - - _, err = self.jsvm.Run("var abi = " + abi + ";") - return - -} - -func (self *NatSpec) SetMethod(method string) (err error) { +func (self *NatSpec) Notice(transaction, abi, method, expression string) (string, error) { + var err error + if _, err = self.jsvm.Run("var transaction = " + transaction + ";"); err != nil { + return "", fmt.Errorf("natspec.js error setting transaction: %v", err) + } - _, err = self.jsvm.Run("var method = '" + method + "';") - return + if _, err = self.jsvm.Run("var abi = " + abi + ";"); err != nil { + return "", fmt.Errorf("natspec.js error setting abi: %v", err) + } -} + if _, err = self.jsvm.Run("var method = '" + method + "';"); err != nil { + return "", fmt.Errorf("natspec.js error setting method: %v", err) + } -func (self *NatSpec) Parse() string { + if _, err = self.jsvm.Run("var expression = \"" + expression + "\";"); err != nil { + return "", fmt.Errorf("natspec.js error setting expression: %v", err) + } self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};") value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);") if err != nil { - return err.Error() + return "", fmt.Errorf("natspec.js error evaluating expression: %v", err) + } + evalError := "Natspec evaluation failed, wrong input params" + if value.String() == evalError { + return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression) } - return value.String() + if len(value.String()) == 0 { + return "", fmt.Errorf("natspec.js error evaluating expression") + } + + return value.String(), nil } diff --git a/ethutil/natspec/natspec.js b/ethutil/natspec/natspec.js deleted file mode 100644 index 419ccd5c9..000000000 --- a/ethutil/natspec/natspec.js +++ /dev/null @@ -1,3517 +0,0 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o. -*/ -/** @file abi.js - * @authors: - * Marek Kotewicz - * Gav Wood - * @date 2014 - */ - -var utils = require('./utils'); -var types = require('./types'); -var c = require('./const'); -var f = require('./formatters'); - -var displayTypeError = function (type) { - console.error('parser does not support type: ' + type); -}; - -/// This method should be called if we want to check if givent type is an array type -/// @returns true if it is, otherwise false -var arrayType = function (type) { - return type.slice(-2) === '[]'; -}; - -var dynamicTypeBytes = function (type, value) { - // TODO: decide what to do with array of strings - if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. - return f.formatInputInt(value.length); - return ""; -}; - -var inputTypes = types.inputTypes(); - -/// Formats input params to bytes -/// @param abi contract method inputs -/// @param array of params that will be formatted to bytes -/// @returns bytes representation of input params -var formatInput = function (inputs, params) { - var bytes = ""; - var toAppendConstant = ""; - var toAppendArrayContent = ""; - - /// first we iterate in search for dynamic - inputs.forEach(function (input, index) { - bytes += dynamicTypeBytes(input.type, params[index]); - }); - - inputs.forEach(function (input, i) { - /*jshint maxcomplexity:5 */ - var typeMatch = false; - for (var j = 0; j < inputTypes.length && !typeMatch; j++) { - typeMatch = inputTypes[j].type(inputs[i].type, params[i]); - } - if (!typeMatch) { - displayTypeError(inputs[i].type); - } - - var formatter = inputTypes[j - 1].format; - - if (arrayType(inputs[i].type)) - toAppendArrayContent += params[i].reduce(function (acc, curr) { - return acc + formatter(curr); - }, ""); - else if (inputs[i].type === 'string') - toAppendArrayContent += formatter(params[i]); - else - toAppendConstant += formatter(params[i]); - }); - - bytes += toAppendConstant + toAppendArrayContent; - - return bytes; -}; - -var dynamicBytesLength = function (type) { - if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. - return c.ETH_PADDING * 2; - return 0; -}; - -var outputTypes = types.outputTypes(); - -/// Formats output bytes back to param list -/// @param contract abi method outputs -/// @param bytes representtion of output -/// @returns array of output params -var formatOutput = function (outs, output) { - - output = output.slice(2); - var result = []; - var padding = c.ETH_PADDING * 2; - - var dynamicPartLength = outs.reduce(function (acc, curr) { - return acc + dynamicBytesLength(curr.type); - }, 0); - - var dynamicPart = output.slice(0, dynamicPartLength); - output = output.slice(dynamicPartLength); - - outs.forEach(function (out, i) { - /*jshint maxcomplexity:6 */ - var typeMatch = false; - for (var j = 0; j < outputTypes.length && !typeMatch; j++) { - typeMatch = outputTypes[j].type(outs[i].type); - } - - if (!typeMatch) { - displayTypeError(outs[i].type); - } - - var formatter = outputTypes[j - 1].format; - if (arrayType(outs[i].type)) { - var size = f.formatOutputUInt(dynamicPart.slice(0, padding)); - dynamicPart = dynamicPart.slice(padding); - var array = []; - for (var k = 0; k < size; k++) { - array.push(formatter(output.slice(0, padding))); - output = output.slice(padding); - } - result.push(array); - } - else if (types.prefixedType('string')(outs[i].type)) { - dynamicPart = dynamicPart.slice(padding); - result.push(formatter(output.slice(0, padding))); - output = output.slice(padding); - } else { - result.push(formatter(output.slice(0, padding))); - output = output.slice(padding); - } - }); - - return result; -}; - -/// @param json abi for contract -/// @returns input parser object for given json abi -/// TODO: refactor creating the parser, do not double logic from contract -var inputParser = function (json) { - var parser = {}; - json.forEach(function (method) { - var displayName = utils.extractDisplayName(method.name); - var typeName = utils.extractTypeName(method.name); - - var impl = function () { - var params = Array.prototype.slice.call(arguments); - return formatInput(method.inputs, params); - }; - - if (parser[displayName] === undefined) { - parser[displayName] = impl; - } - - parser[displayName][typeName] = impl; - }); - - return parser; -}; - -/// @param json abi for contract -/// @returns output parser for given json abi -var outputParser = function (json) { - var parser = {}; - json.forEach(function (method) { - - var displayName = utils.extractDisplayName(method.name); - var typeName = utils.extractTypeName(method.name); - - var impl = function (output) { - return formatOutput(method.outputs, output); - }; - - if (parser[displayName] === undefined) { - parser[displayName] = impl; - } - - parser[displayName][typeName] = impl; - }); - - return parser; -}; - -module.exports = { - inputParser: inputParser, - outputParser: outputParser, - formatInput: formatInput, - formatOutput: formatOutput -}; - -},{"./const":4,"./formatters":5,"./types":6,"./utils":7}],4:[function(require,module,exports){ -(function (process){ -/* - This file is part of ethereum.js. - - ethereum.js 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. - - ethereum.js 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 ethereum.js. If not, see . -*/ -/** @file const.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -/// required to define ETH_BIGNUMBER_ROUNDING_MODE -if (process.env.NODE_ENV !== 'build') { - var BigNumber = require('bignumber.js'); // jshint ignore:line -} - -var ETH_UNITS = [ - 'wei', - 'Kwei', - 'Mwei', - 'Gwei', - 'szabo', - 'finney', - 'ether', - 'grand', - 'Mether', - 'Gether', - 'Tether', - 'Pether', - 'Eether', - 'Zether', - 'Yether', - 'Nether', - 'Dether', - 'Vether', - 'Uether' -]; - -module.exports = { - ETH_PADDING: 32, - ETH_SIGNATURE_LENGTH: 4, - ETH_UNITS: ETH_UNITS, - ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, - ETH_POLLING_TIMEOUT: 1000 -}; - - -}).call(this,require('_process')) -},{"_process":2,"bignumber.js":8}],5:[function(require,module,exports){ -(function (process){ -/* - This file is part of ethereum.js. - - ethereum.js 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. - - ethereum.js 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 ethereum.js. If not, see . -*/ -/** @file formatters.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -if (process.env.NODE_ENV !== 'build') { - var BigNumber = require('bignumber.js'); // jshint ignore:line -} - -var utils = require('./utils'); -var c = require('./const'); - -/// @param string string to be padded -/// @param number of characters that result string should have -/// @param sign, by default 0 -/// @returns right aligned string -var padLeft = function (string, chars, sign) { - return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; -}; - -/// Formats input value to byte representation of int -/// If value is negative, return it's two's complement -/// If the value is floating point, round it down -/// @returns right-aligned byte representation of int -var formatInputInt = function (value) { - /*jshint maxcomplexity:7 */ - var padding = c.ETH_PADDING * 2; - if (value instanceof BigNumber || typeof value === 'number') { - if (typeof value === 'number') - value = new BigNumber(value); - BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE); - value = value.round(); - - if (value.lessThan(0)) - value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1); - value = value.toString(16); - } - else if (value.indexOf('0x') === 0) - value = value.substr(2); - else if (typeof value === 'string') - value = formatInputInt(new BigNumber(value)); - else - value = (+value).toString(16); - return padLeft(value, padding); -}; - -/// Formats input value to byte representation of string -/// @returns left-algined byte representation of string -var formatInputString = function (value) { - return utils.fromAscii(value, c.ETH_PADDING).substr(2); -}; - -/// Formats input value to byte representation of bool -/// @returns right-aligned byte representation bool -var formatInputBool = function (value) { - return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0'); -}; - -/// Formats input value to byte representation of real -/// Values are multiplied by 2^m and encoded as integers -/// @returns byte representation of real -var formatInputReal = function (value) { - return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); -}; - - -/// Check if input value is negative -/// @param value is hex format -/// @returns true if it is negative, otherwise false -var signedIsNegative = function (value) { - return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; -}; - -/// Formats input right-aligned input bytes to int -/// @returns right-aligned input bytes formatted to int -var formatOutputInt = function (value) { - value = value || "0"; - // check if it's negative number - // it it is, return two's complement - if (signedIsNegative(value)) { - return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1); - } - return new BigNumber(value, 16); -}; - -/// Formats big right-aligned input bytes to uint -/// @returns right-aligned input bytes formatted to uint -var formatOutputUInt = function (value) { - value = value || "0"; - return new BigNumber(value, 16); -}; - -/// @returns input bytes formatted to real -var formatOutputReal = function (value) { - return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); -}; - -/// @returns input bytes formatted to ureal -var formatOutputUReal = function (value) { - return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); -}; - -/// @returns right-aligned input bytes formatted to hex -var formatOutputHash = function (value) { - return "0x" + value; -}; - -/// @returns right-aligned input bytes formatted to bool -var formatOutputBool = function (value) { - return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; -}; - -/// @returns left-aligned input bytes formatted to ascii string -var formatOutputString = function (value) { - return utils.toAscii(value); -}; - -/// @returns right-aligned input bytes formatted to address -var formatOutputAddress = function (value) { - return "0x" + value.slice(value.length - 40, value.length); -}; - - -module.exports = { - formatInputInt: formatInputInt, - formatInputString: formatInputString, - formatInputBool: formatInputBool, - formatInputReal: formatInputReal, - formatOutputInt: formatOutputInt, - formatOutputUInt: formatOutputUInt, - formatOutputReal: formatOutputReal, - formatOutputUReal: formatOutputUReal, - formatOutputHash: formatOutputHash, - formatOutputBool: formatOutputBool, - formatOutputString: formatOutputString, - formatOutputAddress: formatOutputAddress -}; - - -}).call(this,require('_process')) -},{"./const":4,"./utils":7,"_process":2,"bignumber.js":8}],6:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js 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. - - ethereum.js 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 ethereum.js. If not, see . -*/ -/** @file types.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var f = require('./formatters'); - -/// @param expected type prefix (string) -/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false -var prefixedType = function (prefix) { - return function (type) { - return type.indexOf(prefix) === 0; - }; -}; - -/// @param expected type name (string) -/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false -var namedType = function (name) { - return function (type) { - return name === type; - }; -}; - -/// Setups input formatters for solidity types -/// @returns an array of input formatters -var inputTypes = function () { - - return [ - { type: prefixedType('uint'), format: f.formatInputInt }, - { type: prefixedType('int'), format: f.formatInputInt }, - { type: prefixedType('hash'), format: f.formatInputInt }, - { type: prefixedType('string'), format: f.formatInputString }, - { type: prefixedType('real'), format: f.formatInputReal }, - { type: prefixedType('ureal'), format: f.formatInputReal }, - { type: namedType('address'), format: f.formatInputInt }, - { type: namedType('bool'), format: f.formatInputBool } - ]; -}; - -/// Setups output formaters for solidity types -/// @returns an array of output formatters -var outputTypes = function () { - - return [ - { type: prefixedType('uint'), format: f.formatOutputUInt }, - { type: prefixedType('int'), format: f.formatOutputInt }, - { type: prefixedType('hash'), format: f.formatOutputHash }, - { type: prefixedType('string'), format: f.formatOutputString }, - { type: prefixedType('real'), format: f.formatOutputReal }, - { type: prefixedType('ureal'), format: f.formatOutputUReal }, - { type: namedType('address'), format: f.formatOutputAddress }, - { type: namedType('bool'), format: f.formatOutputBool } - ]; -}; - -module.exports = { - prefixedType: prefixedType, - namedType: namedType, - inputTypes: inputTypes, - outputTypes: outputTypes -}; - - -},{"./formatters":5}],7:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js 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. - - ethereum.js 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 ethereum.js. If not, see . -*/ -/** @file utils.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var c = require('./const'); - -/// Finds first index of array element matching pattern -/// @param array -/// @param callback pattern -/// @returns index of element -var findIndex = function (array, callback) { - var end = false; - var i = 0; - for (; i < array.length && !end; i++) { - end = callback(array[i]); - } - return end ? i - 1 : -1; -}; - -/// @returns ascii string representation of hex value prefixed with 0x -var toAscii = function(hex) { -// Find termination - var str = ""; - var i = 0, l = hex.length; - if (hex.substring(0, 2) === '0x') { - i = 2; - } - for (; i < l; i+=2) { - var code = parseInt(hex.substr(i, 2), 16); - if (code === 0) { - break; - } - - str += String.fromCharCode(code); - } - - return str; -}; - -var toHex = function(str) { - var hex = ""; - for(var i = 0; i < str.length; i++) { - var n = str.charCodeAt(i).toString(16); - hex += n.length < 2 ? '0' + n : n; - } - - return hex; -}; - -/// @returns hex representation (prefixed by 0x) of ascii string -var fromAscii = function(str, pad) { - pad = pad === undefined ? 0 : pad; - var hex = toHex(str); - while (hex.length < pad*2) - hex += "00"; - return "0x" + hex; -}; - -/// @returns display name for function/event eg. multiply(uint256) -> multiply -var extractDisplayName = function (name) { - var length = name.indexOf('('); - return length !== -1 ? name.substr(0, length) : name; -}; - -/// @returns overloaded part of function/event name -var extractTypeName = function (name) { - /// TODO: make it invulnerable - var length = name.indexOf('('); - return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; -}; - -/// Filters all function from input abi -/// @returns abi array with filtered objects of type 'function' -var filterFunctions = function (json) { - return json.filter(function (current) { - return current.type === 'function'; - }); -}; - -/// Filters all events form input abi -/// @returns abi array with filtered objects of type 'event' -var filterEvents = function (json) { - return json.filter(function (current) { - return current.type === 'event'; - }); -}; - -/// used to transform value/string to eth string -/// TODO: use BigNumber.js to parse int -/// TODO: add tests for it! -var toEth = function (str) { - /*jshint maxcomplexity:7 */ - var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; - var unit = 0; - var units = c.ETH_UNITS; - while (val > 3000 && unit < units.length - 1) - { - val /= 1000; - unit++; - } - var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); - var replaceFunction = function($0, $1, $2) { - return $1 + ',' + $2; - }; - - while (true) { - var o = s; - s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction); - if (o === s) - break; - } - return s + ' ' + units[unit]; -}; - -module.exports = { - findIndex: findIndex, - toAscii: toAscii, - fromAscii: fromAscii, - extractDisplayName: extractDisplayName, - extractTypeName: extractTypeName, - filterFunctions: filterFunctions, - filterEvents: filterEvents, - toEth: toEth -}; - - -},{"./const":4}],8:[function(require,module,exports){ -/*! bignumber.js v2.0.3 https://github.com/MikeMcl/bignumber.js/LICENCE */ - -;(function (global) { - 'use strict'; - - /* - bignumber.js v2.0.3 - A JavaScript library for arbitrary-precision arithmetic. - https://github.com/MikeMcl/bignumber.js - Copyright (c) 2015 Michael Mclaughlin - MIT Expat Licence - */ - - - var BigNumber, crypto, parseNumeric, - isNumeric = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, - mathceil = Math.ceil, - mathfloor = Math.floor, - notBool = ' not a boolean or binary digit', - roundingMode = 'rounding mode', - tooManyDigits = 'number type has more than 15 significant digits', - ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_', - BASE = 1e14, - LOG_BASE = 14, - MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1 - // MAX_INT32 = 0x7fffffff, // 2^31 - 1 - POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], - SQRT_BASE = 1e7, - - /* - * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and - * the arguments to toExponential, toFixed, toFormat, and toPrecision, beyond which an - * exception is thrown (if ERRORS is true). - */ - MAX = 1E9; // 0 to MAX_INT32 - - - /* - * Create and return a BigNumber constructor. - */ - function another(configObj) { - var div, - - // id tracks the caller function, so its name can be included in error messages. - id = 0, - P = BigNumber.prototype, - ONE = new BigNumber(1), - - - /********************************* EDITABLE DEFAULTS **********************************/ - - - /* - * The default values below must be integers within the inclusive ranges stated. - * The values can also be changed at run-time using BigNumber.config. - */ - - // The maximum number of decimal places for operations involving division. - DECIMAL_PLACES = 20, // 0 to MAX - - /* - * The rounding mode used when rounding to the above decimal places, and when using - * toExponential, toFixed, toFormat and toPrecision, and round (default value). - * UP 0 Away from zero. - * DOWN 1 Towards zero. - * CEIL 2 Towards +Infinity. - * FLOOR 3 Towards -Infinity. - * HALF_UP 4 Towards nearest neighbour. If equidistant, up. - * HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. - * HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. - * HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. - * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. - */ - ROUNDING_MODE = 4, // 0 to 8 - - // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS] - - // The exponent value at and beneath which toString returns exponential notation. - // Number type: -7 - TO_EXP_NEG = -7, // 0 to -MAX - - // The exponent value at and above which toString returns exponential notation. - // Number type: 21 - TO_EXP_POS = 21, // 0 to MAX - - // RANGE : [MIN_EXP, MAX_EXP] - - // The minimum exponent value, beneath which underflow to zero occurs. - // Number type: -324 (5e-324) - MIN_EXP = -1e7, // -1 to -MAX - - // The maximum exponent value, above which overflow to Infinity occurs. - // Number type: 308 (1.7976931348623157e+308) - // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow. - MAX_EXP = 1e7, // 1 to MAX - - // Whether BigNumber Errors are ever thrown. - ERRORS = true, // true or false - - // Change to intValidatorNoErrors if ERRORS is false. - isValidInt = intValidatorWithErrors, // intValidatorWithErrors/intValidatorNoErrors - - // Whether to use cryptographically-secure random number generation, if available. - CRYPTO = false, // true or false - - /* - * The modulo mode used when calculating the modulus: a mod n. - * The quotient (q = a / n) is calculated according to the corresponding rounding mode. - * The remainder (r) is calculated as: r = a - n * q. - * - * UP 0 The remainder is positive if the dividend is negative, else is negative. - * DOWN 1 The remainder has the same sign as the dividend. - * This modulo mode is commonly known as 'truncated division' and is - * equivalent to (a % n) in JavaScript. - * FLOOR 3 The remainder has the same sign as the divisor (Python %). - * HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function. - * EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). - * The remainder is always positive. - * - * The truncated division, floored division, Euclidian division and IEEE 754 remainder - * modes are commonly used for the modulus operation. - * Although the other rounding modes can also be used, they may not give useful results. - */ - MODULO_MODE = 1, // 0 to 9 - - // The maximum number of significant digits of the result of the toPower operation. - // If POW_PRECISION is 0, there will be unlimited significant digits. - POW_PRECISION = 100, // 0 to MAX - - // The format specification used by the BigNumber.prototype.toFormat method. - FORMAT = { - decimalSeparator: '.', - groupSeparator: ',', - groupSize: 3, - secondaryGroupSize: 0, - fractionGroupSeparator: '\xA0', // non-breaking space - fractionGroupSize: 0 - }; - - - /******************************************************************************************/ - - - // CONSTRUCTOR - - - /* - * The BigNumber constructor and exported function. - * Create and return a new instance of a BigNumber object. - * - * n {number|string|BigNumber} A numeric value. - * [b] {number} The base of n. Integer, 2 to 64 inclusive. - */ - function BigNumber( n, b ) { - var c, e, i, num, len, str, - x = this; - - // Enable constructor usage without new. - if ( !( x instanceof BigNumber ) ) { - - // 'BigNumber() constructor call without new: {n}' - if (ERRORS) raise( 26, 'constructor call without new', n ); - return new BigNumber( n, b ); - } - - // 'new BigNumber() base not an integer: {b}' - // 'new BigNumber() base out of range: {b}' - if ( b == null || !isValidInt( b, 2, 64, id, 'base' ) ) { - - // Duplicate. - if ( n instanceof BigNumber ) { - x.s = n.s; - x.e = n.e; - x.c = ( n = n.c ) ? n.slice() : n; - id = 0; - return; - } - - if ( ( num = typeof n == 'number' ) && n * 0 == 0 ) { - x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1; - - // Fast path for integers. - if ( n === ~~n ) { - for ( e = 0, i = n; i >= 10; i /= 10, e++ ); - x.e = e; - x.c = [n]; - id = 0; - return; - } - - str = n + ''; - } else { - if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, num ); - x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; - } - } else { - b = b | 0; - str = n + ''; - - // Ensure return value is rounded to DECIMAL_PLACES as with other bases. - // Allow exponential notation to be used with base 10 argument. - if ( b == 10 ) { - x = new BigNumber( n instanceof BigNumber ? n : str ); - return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE ); - } - - // Avoid potential interpretation of Infinity and NaN as base 44+ values. - // Any number in exponential form will fail due to the [Ee][+-]. - if ( ( num = typeof n == 'number' ) && n * 0 != 0 || - !( new RegExp( '^-?' + ( c = '[' + ALPHABET.slice( 0, b ) + ']+' ) + - '(?:\\.' + c + ')?$',b < 37 ? 'i' : '' ) ).test(str) ) { - return parseNumeric( x, str, num, b ); - } - - if (num) { - x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1; - - if ( ERRORS && str.replace( /^0\.0*|\./, '' ).length > 15 ) { - - // 'new BigNumber() number type has more than 15 significant digits: {n}' - raise( id, tooManyDigits, n ); - } - - // Prevent later check for length on converted number. - num = false; - } else { - x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; - } - - str = convertBase( str, 10, b, x.s ); - } - - // Decimal point? - if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' ); - - // Exponential form? - if ( ( i = str.search( /e/i ) ) > 0 ) { - - // Determine exponent. - if ( e < 0 ) e = i; - e += +str.slice( i + 1 ); - str = str.substring( 0, i ); - } else if ( e < 0 ) { - - // Integer. - e = str.length; - } - - // Determine leading zeros. - for ( i = 0; str.charCodeAt(i) === 48; i++ ); - - // Determine trailing zeros. - for ( len = str.length; str.charCodeAt(--len) === 48; ); - str = str.slice( i, len + 1 ); - - if (str) { - len = str.length; - - // Disallow numbers with over 15 significant digits if number type. - // 'new BigNumber() number type has more than 15 significant digits: {n}' - if ( num && ERRORS && len > 15 ) raise( id, tooManyDigits, x.s * n ); - - e = e - i - 1; - - // Overflow? - if ( e > MAX_EXP ) { - - // Infinity. - x.c = x.e = null; - - // Underflow? - } else if ( e < MIN_EXP ) { - - // Zero. - x.c = [ x.e = 0 ]; - } else { - x.e = e; - x.c = []; - - // Transform base - - // e is the base 10 exponent. - // i is where to slice str to get the first element of the coefficient array. - i = ( e + 1 ) % LOG_BASE; - if ( e < 0 ) i += LOG_BASE; - - if ( i < len ) { - if (i) x.c.push( +str.slice( 0, i ) ); - - for ( len -= LOG_BASE; i < len; ) { - x.c.push( +str.slice( i, i += LOG_BASE ) ); - } - - str = str.slice(i); - i = LOG_BASE - str.length; - } else { - i -= len; - } - - for ( ; i--; str += '0' ); - x.c.push( +str ); - } - } else { - - // Zero. - x.c = [ x.e = 0 ]; - } - - id = 0; - } - - - // CONSTRUCTOR PROPERTIES - - - BigNumber.another = another; - - BigNumber.ROUND_UP = 0; - BigNumber.ROUND_DOWN = 1; - BigNumber.ROUND_CEIL = 2; - BigNumber.ROUND_FLOOR = 3; - BigNumber.ROUND_HALF_UP = 4; - BigNumber.ROUND_HALF_DOWN = 5; - BigNumber.ROUND_HALF_EVEN = 6; - BigNumber.ROUND_HALF_CEIL = 7; - BigNumber.ROUND_HALF_FLOOR = 8; - BigNumber.EUCLID = 9; - - - /* - * Configure infrequently-changing library-wide settings. - * - * Accept an object or an argument list, with one or many of the following properties or - * parameters respectively: - * - * DECIMAL_PLACES {number} Integer, 0 to MAX inclusive - * ROUNDING_MODE {number} Integer, 0 to 8 inclusive - * EXPONENTIAL_AT {number|number[]} Integer, -MAX to MAX inclusive or - * [integer -MAX to 0 incl., 0 to MAX incl.] - * RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or - * [integer -MAX to -1 incl., integer 1 to MAX incl.] - * ERRORS {boolean|number} true, false, 1 or 0 - * CRYPTO {boolean|number} true, false, 1 or 0 - * MODULO_MODE {number} 0 to 9 inclusive - * POW_PRECISION {number} 0 to MAX inclusive - * FORMAT {object} See BigNumber.prototype.toFormat - * decimalSeparator {string} - * groupSeparator {string} - * groupSize {number} - * secondaryGroupSize {number} - * fractionGroupSeparator {string} - * fractionGroupSize {number} - * - * (The values assigned to the above FORMAT object properties are not checked for validity.) - * - * E.g. - * BigNumber.config(20, 4) is equivalent to - * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 }) - * - * Ignore properties/parameters set to null or undefined. - * Return an object with the properties current values. - */ - BigNumber.config = function () { - var v, p, - i = 0, - r = {}, - a = arguments, - o = a[0], - has = o && typeof o == 'object' - ? function () { if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null; } - : function () { if ( a.length > i ) return ( v = a[i++] ) != null; }; - - // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive. - // 'config() DECIMAL_PLACES not an integer: {v}' - // 'config() DECIMAL_PLACES out of range: {v}' - if ( has( p = 'DECIMAL_PLACES' ) && isValidInt( v, 0, MAX, 2, p ) ) { - DECIMAL_PLACES = v | 0; - } - r[p] = DECIMAL_PLACES; - - // ROUNDING_MODE {number} Integer, 0 to 8 inclusive. - // 'config() ROUNDING_MODE not an integer: {v}' - // 'config() ROUNDING_MODE out of range: {v}' - if ( has( p = 'ROUNDING_MODE' ) && isValidInt( v, 0, 8, 2, p ) ) { - ROUNDING_MODE = v | 0; - } - r[p] = ROUNDING_MODE; - - // EXPONENTIAL_AT {number|number[]} - // Integer, -MAX to MAX inclusive or [integer -MAX to 0 inclusive, 0 to MAX inclusive]. - // 'config() EXPONENTIAL_AT not an integer: {v}' - // 'config() EXPONENTIAL_AT out of range: {v}' - if ( has( p = 'EXPONENTIAL_AT' ) ) { - - if ( isArray(v) ) { - if ( isValidInt( v[0], -MAX, 0, 2, p ) && isValidInt( v[1], 0, MAX, 2, p ) ) { - TO_EXP_NEG = v[0] | 0; - TO_EXP_POS = v[1] | 0; - } - } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) { - TO_EXP_NEG = -( TO_EXP_POS = ( v < 0 ? -v : v ) | 0 ); - } - } - r[p] = [ TO_EXP_NEG, TO_EXP_POS ]; - - // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or - // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive]. - // 'config() RANGE not an integer: {v}' - // 'config() RANGE cannot be zero: {v}' - // 'config() RANGE out of range: {v}' - if ( has( p = 'RANGE' ) ) { - - if ( isArray(v) ) { - if ( isValidInt( v[0], -MAX, -1, 2, p ) && isValidInt( v[1], 1, MAX, 2, p ) ) { - MIN_EXP = v[0] | 0; - MAX_EXP = v[1] | 0; - } - } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) { - if ( v | 0 ) MIN_EXP = -( MAX_EXP = ( v < 0 ? -v : v ) | 0 ); - else if (ERRORS) raise( 2, p + ' cannot be zero', v ); - } - } - r[p] = [ MIN_EXP, MAX_EXP ]; - - // ERRORS {boolean|number} true, false, 1 or 0. - // 'config() ERRORS not a boolean or binary digit: {v}' - if ( has( p = 'ERRORS' ) ) { - - if ( v === !!v || v === 1 || v === 0 ) { - id = 0; - isValidInt = ( ERRORS = !!v ) ? intValidatorWithErrors : intValidatorNoErrors; - } else if (ERRORS) { - raise( 2, p + notBool, v ); - } - } - r[p] = ERRORS; - - // CRYPTO {boolean|number} true, false, 1 or 0. - // 'config() CRYPTO not a boolean or binary digit: {v}' - // 'config() crypto unavailable: {crypto}' - if ( has( p = 'CRYPTO' ) ) { - - if ( v === !!v || v === 1 || v === 0 ) { - CRYPTO = !!( v && crypto && typeof crypto == 'object' ); - if ( v && !CRYPTO && ERRORS ) raise( 2, 'crypto unavailable', crypto ); - } else if (ERRORS) { - raise( 2, p + notBool, v ); - } - } - r[p] = CRYPTO; - - // MODULO_MODE {number} Integer, 0 to 9 inclusive. - // 'config() MODULO_MODE not an integer: {v}' - // 'config() MODULO_MODE out of range: {v}' - if ( has( p = 'MODULO_MODE' ) && isValidInt( v, 0, 9, 2, p ) ) { - MODULO_MODE = v | 0; - } - r[p] = MODULO_MODE; - - // POW_PRECISION {number} Integer, 0 to MAX inclusive. - // 'config() POW_PRECISION not an integer: {v}' - // 'config() POW_PRECISION out of range: {v}' - if ( has( p = 'POW_PRECISION' ) && isValidInt( v, 0, MAX, 2, p ) ) { - POW_PRECISION = v | 0; - } - r[p] = POW_PRECISION; - - // FORMAT {object} - // 'config() FORMAT not an object: {v}' - if ( has( p = 'FORMAT' ) ) { - - if ( typeof v == 'object' ) { - FORMAT = v; - } else if (ERRORS) { - raise( 2, p + ' not an object', v ); - } - } - r[p] = FORMAT; - - return r; - }; - - - /* - * Return a new BigNumber whose value is the maximum of the arguments. - * - * arguments {number|string|BigNumber} - */ - BigNumber.max = function () { return maxOrMin( arguments, P.lt ); }; - - - /* - * Return a new BigNumber whose value is the minimum of the arguments. - * - * arguments {number|string|BigNumber} - */ - BigNumber.min = function () { return maxOrMin( arguments, P.gt ); }; - - - /* - * Return a new BigNumber with a random value equal to or greater than 0 and less than 1, - * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing - * zeros are produced). - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * - * 'random() decimal places not an integer: {dp}' - * 'random() decimal places out of range: {dp}' - * 'random() crypto unavailable: {crypto}' - */ - BigNumber.random = (function () { - var pow2_53 = 0x20000000000000; - - // Return a 53 bit integer n, where 0 <= n < 9007199254740992. - // Check if Math.random() produces more than 32 bits of randomness. - // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits. - // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1. - var random53bitInt = (Math.random() * pow2_53) & 0x1fffff - ? function () { return mathfloor( Math.random() * pow2_53 ); } - : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) + - (Math.random() * 0x800000 | 0); }; - - return function (dp) { - var a, b, e, k, v, - i = 0, - c = [], - rand = new BigNumber(ONE); - - dp = dp == null || !isValidInt( dp, 0, MAX, 14 ) ? DECIMAL_PLACES : dp | 0; - k = mathceil( dp / LOG_BASE ); - - if (CRYPTO) { - - // Browsers supporting crypto.getRandomValues. - if ( crypto && crypto.getRandomValues ) { - - a = crypto.getRandomValues( new Uint32Array( k *= 2 ) ); - - for ( ; i < k; ) { - - // 53 bits: - // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2) - // 11111 11111111 11111111 11111111 11100000 00000000 00000000 - // ((Math.pow(2, 32) - 1) >>> 11).toString(2) - // 11111 11111111 11111111 - // 0x20000 is 2^21. - v = a[i] * 0x20000 + (a[i + 1] >>> 11); - - // Rejection sampling: - // 0 <= v < 9007199254740992 - // Probability that v >= 9e15, is - // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251 - if ( v >= 9e15 ) { - b = crypto.getRandomValues( new Uint32Array(2) ); - a[i] = b[0]; - a[i + 1] = b[1]; - } else { - - // 0 <= v <= 8999999999999999 - // 0 <= (v % 1e14) <= 99999999999999 - c.push( v % 1e14 ); - i += 2; - } - } - i = k / 2; - - // Node.js supporting crypto.randomBytes. - } else if ( crypto && crypto.randomBytes ) { - - // buffer - a = crypto.randomBytes( k *= 7 ); - - for ( ; i < k; ) { - - // 0x1000000000000 is 2^48, 0x10000000000 is 2^40 - // 0x100000000 is 2^32, 0x1000000 is 2^24 - // 11111 11111111 11111111 11111111 11111111 11111111 11111111 - // 0 <= v < 9007199254740992 - v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) + - ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) + - ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6]; - - if ( v >= 9e15 ) { - crypto.randomBytes(7).copy( a, i ); - } else { - - // 0 <= (v % 1e14) <= 99999999999999 - c.push( v % 1e14 ); - i += 7; - } - } - i = k / 7; - } else if (ERRORS) { - raise( 14, 'crypto unavailable', crypto ); - } - } - - // Use Math.random: CRYPTO is false or crypto is unavailable and ERRORS is false. - if (!i) { - - for ( ; i < k; ) { - v = random53bitInt(); - if ( v < 9e15 ) c[i++] = v % 1e14; - } - } - - k = c[--i]; - dp %= LOG_BASE; - - // Convert trailing digits to zeros according to dp. - if ( k && dp ) { - v = POWS_TEN[LOG_BASE - dp]; - c[i] = mathfloor( k / v ) * v; - } - - // Remove trailing elements which are zero. - for ( ; c[i] === 0; c.pop(), i-- ); - - // Zero? - if ( i < 0 ) { - c = [ e = 0 ]; - } else { - - // Remove leading elements which are zero and adjust exponent accordingly. - for ( e = -1 ; c[0] === 0; c.shift(), e -= LOG_BASE); - - // Count the digits of the first element of c to determine leading zeros, and... - for ( i = 1, v = c[0]; v >= 10; v /= 10, i++); - - // adjust the exponent accordingly. - if ( i < LOG_BASE ) e -= LOG_BASE - i; - } - - rand.e = e; - rand.c = c; - return rand; - }; - })(); - - - // PRIVATE FUNCTIONS - - - // Convert a numeric string of baseIn to a numeric string of baseOut. - function convertBase( str, baseOut, baseIn, sign ) { - var d, e, k, r, x, xc, y, - i = str.indexOf( '.' ), - dp = DECIMAL_PLACES, - rm = ROUNDING_MODE; - - if ( baseIn < 37 ) str = str.toLowerCase(); - - // Non-integer. - if ( i >= 0 ) { - k = POW_PRECISION; - - // Unlimited precision. - POW_PRECISION = 0; - str = str.replace( '.', '' ); - y = new BigNumber(baseIn); - x = y.pow( str.length - i ); - POW_PRECISION = k; - - // Convert str as if an integer, then restore the fraction part by dividing the - // result by its base raised to a power. - y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e ), 10, baseOut ); - y.e = y.c.length; - } - - // Convert the number as integer. - xc = toBaseOut( str, baseIn, baseOut ); - e = k = xc.length; - - // Remove trailing zeros. - for ( ; xc[--k] == 0; xc.pop() ); - if ( !xc[0] ) return '0'; - - if ( i < 0 ) { - --e; - } else { - x.c = xc; - x.e = e; - - // sign is needed for correct rounding. - x.s = sign; - x = div( x, y, dp, rm, baseOut ); - xc = x.c; - r = x.r; - e = x.e; - } - - d = e + dp + 1; - - // The rounding digit, i.e. the digit to the right of the digit that may be rounded up. - i = xc[d]; - k = baseOut / 2; - r = r || d < 0 || xc[d + 1] != null; - - r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) - : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 || - rm == ( x.s < 0 ? 8 : 7 ) ); - - if ( d < 1 || !xc[0] ) { - - // 1^-dp or 0. - str = r ? toFixedPoint( '1', -dp ) : '0'; - } else { - xc.length = d; - - if (r) { - - // Rounding up may mean the previous digit has to be rounded up and so on. - for ( --baseOut; ++xc[--d] > baseOut; ) { - xc[d] = 0; - - if ( !d ) { - ++e; - xc.unshift(1); - } - } - } - - // Determine trailing zeros. - for ( k = xc.length; !xc[--k]; ); - - // E.g. [4, 11, 15] becomes 4bf. - for ( i = 0, str = ''; i <= k; str += ALPHABET.charAt( xc[i++] ) ); - str = toFixedPoint( str, e ); - } - - // The caller will add the sign. - return str; - } - - - // Perform division in the specified base. Called by div and convertBase. - div = (function () { - - // Assume non-zero x and k. - function multiply( x, k, base ) { - var m, temp, xlo, xhi, - carry = 0, - i = x.length, - klo = k % SQRT_BASE, - khi = k / SQRT_BASE | 0; - - for ( x = x.slice(); i--; ) { - xlo = x[i] % SQRT_BASE; - xhi = x[i] / SQRT_BASE | 0; - m = khi * xlo + xhi * klo; - temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry; - carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi; - x[i] = temp % base; - } - - if (carry) x.unshift(carry); - - return x; - } - - function compare( a, b, aL, bL ) { - var i, cmp; - - if ( aL != bL ) { - cmp = aL > bL ? 1 : -1; - } else { - - for ( i = cmp = 0; i < aL; i++ ) { - - if ( a[i] != b[i] ) { - cmp = a[i] > b[i] ? 1 : -1; - break; - } - } - } - return cmp; - } - - function subtract( a, b, aL, base ) { - var i = 0; - - // Subtract b from a. - for ( ; aL--; ) { - a[aL] -= i; - i = a[aL] < b[aL] ? 1 : 0; - a[aL] = i * base + a[aL] - b[aL]; - } - - // Remove leading zeros. - for ( ; !a[0] && a.length > 1; a.shift() ); - } - - // x: dividend, y: divisor. - return function ( x, y, dp, rm, base ) { - var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0, - yL, yz, - s = x.s == y.s ? 1 : -1, - xc = x.c, - yc = y.c; - - // Either NaN, Infinity or 0? - if ( !xc || !xc[0] || !yc || !yc[0] ) { - - return new BigNumber( - - // Return NaN if either NaN, or both Infinity or 0. - !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN : - - // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0. - xc && xc[0] == 0 || !yc ? s * 0 : s / 0 - ); - } - - q = new BigNumber(s); - qc = q.c = []; - e = x.e - y.e; - s = dp + e + 1; - - if ( !base ) { - base = BASE; - e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE ); - s = s / LOG_BASE | 0; - } - - // Result exponent may be one less then the current value of e. - // The coefficients of the BigNumbers from convertBase may have trailing zeros. - for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ ); - if ( yc[i] > ( xc[i] || 0 ) ) e--; - - if ( s < 0 ) { - qc.push(1); - more = true; - } else { - xL = xc.length; - yL = yc.length; - i = 0; - s += 2; - - // Normalise xc and yc so highest order digit of yc is >= base/2 - - n = mathfloor( base / ( yc[0] + 1 ) ); - - if ( n > 1 ) { - yc = multiply( yc, n, base ); - xc = multiply( xc, n, base ); - yL = yc.length; - xL = xc.length; - } - - xi = yL; - rem = xc.slice( 0, yL ); - remL = rem.length; - - // Add zeros to make remainder as long as divisor. - for ( ; remL < yL; rem[remL++] = 0 ); - yz = yc.slice(); - yz.unshift(0); - yc0 = yc[0]; - if ( yc[1] >= base / 2 ) yc0++; - - do { - n = 0; - - // Compare divisor and remainder. - cmp = compare( yc, rem, yL, remL ); - - // If divisor < remainder. - if ( cmp < 0 ) { - - // Calculate trial digit, n. - - rem0 = rem[0]; - if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 ); - - // n is how many times the divisor goes into the current remainder. - n = mathfloor( rem0 / yc0 ); - - // Algorithm: - // 1. product = divisor * trial digit (n) - // 2. if product > remainder: product -= divisor, n-- - // 3. remainder -= product - // 4. if product was < remainder at 2: - // 5. compare new remainder and divisor - // 6. If remainder > divisor: remainder -= divisor, n++ - - if ( n > 1 ) { - if ( n >= base ) n = base - 1; - - // product = divisor * trial digit. - prod = multiply( yc, n, base ); - prodL = prod.length; - remL = rem.length; - - // Compare product and remainder. - cmp = compare( prod, rem, prodL, remL ); - - // product > remainder. - if ( cmp == 1 ) { - n--; - - // Subtract divisor from product. - subtract( prod, yL < prodL ? yz : yc, prodL, base ); - } - } else { - - // cmp is -1. - // If n is 0, there is no need to compare yc and rem again - // below, so change cmp to 1 to avoid it. - // If n is 1, compare yc and rem again below. - if ( n == 0 ) cmp = n = 1; - prod = yc.slice(); - } - - prodL = prod.length; - if ( prodL < remL ) prod.unshift(0); - - // Subtract product from remainder. - subtract( rem, prod, remL, base ); - - // If product was < previous remainder. - if ( cmp == -1 ) { - remL = rem.length; - - // Compare divisor and new remainder. - cmp = compare( yc, rem, yL, remL ); - - // If divisor < new remainder, subtract divisor from remainder. - if ( cmp < 1 ) { - n++; - - // Subtract divisor from remainder. - subtract( rem, yL < remL ? yz : yc, remL, base ); - } - } - remL = rem.length; - } else if ( cmp === 0 ) { - n++; - rem = [0]; - } - // if cmp === 1, n will be 0 - - // Add the next digit, n, to the result array. - qc[i++] = n; - - // Update the remainder. - if ( cmp && rem[0] ) { - rem[remL++] = xc[xi] || 0; - } else { - rem = [ xc[xi] ]; - remL = 1; - } - } while ( ( xi++ < xL || rem[0] != null ) && s-- ); - - more = rem[0] != null; - - // Leading zero? - if ( !qc[0] ) qc.shift(); - } - - if ( base == BASE ) { - - // To calculate q.e, first get the number of digits of qc[0]. - for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ ); - round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more ); - - // Caller is convertBase. - } else { - q.e = e; - q.r = +more; - } - - return q; - }; - })(); - - - /* - * Return a string representing the value of BigNumber n in fixed-point or exponential - * notation rounded to the specified decimal places or significant digits. - * - * n is a BigNumber. - * i is the index of the last digit required (i.e. the digit that may be rounded up). - * rm is the rounding mode. - * caller is caller id: toExponential 19, toFixed 20, toFormat 21, toPrecision 24. - */ - function format( n, i, rm, caller ) { - var c0, e, ne, len, str; - - rm = rm != null && isValidInt( rm, 0, 8, caller, roundingMode ) - ? rm | 0 : ROUNDING_MODE; - - if ( !n.c ) return n.toString(); - c0 = n.c[0]; - ne = n.e; - - if ( i == null ) { - str = coeffToString( n.c ); - str = caller == 19 || caller == 24 && ne <= TO_EXP_NEG - ? toExponential( str, ne ) - : toFixedPoint( str, ne ); - } else { - n = round( new BigNumber(n), i, rm ); - - // n.e may have changed if the value was rounded up. - e = n.e; - - str = coeffToString( n.c ); - len = str.length; - - // toPrecision returns exponential notation if the number of significant digits - // specified is less than the number of digits necessary to represent the integer - // part of the value in fixed-point notation. - - // Exponential notation. - if ( caller == 19 || caller == 24 && ( i <= e || e <= TO_EXP_NEG ) ) { - - // Append zeros? - for ( ; len < i; str += '0', len++ ); - str = toExponential( str, e ); - - // Fixed-point notation. - } else { - i -= ne; - str = toFixedPoint( str, e ); - - // Append zeros? - if ( e + 1 > len ) { - if ( --i > 0 ) for ( str += '.'; i--; str += '0' ); - } else { - i += e - len; - if ( i > 0 ) { - if ( e + 1 == len ) str += '.'; - for ( ; i--; str += '0' ); - } - } - } - } - - return n.s < 0 && c0 ? '-' + str : str; - } - - - // Handle BigNumber.max and BigNumber.min. - function maxOrMin( args, method ) { - var m, n, - i = 0; - - if ( isArray( args[0] ) ) args = args[0]; - m = new BigNumber( args[0] ); - - for ( ; ++i < args.length; ) { - n = new BigNumber( args[i] ); - - // If any number is NaN, return NaN. - if ( !n.s ) { - m = n; - break; - } else if ( method.call( m, n ) ) { - m = n; - } - } - - return m; - } - - - /* - * Return true if n is an integer in range, otherwise throw. - * Use for argument validation when ERRORS is true. - */ - function intValidatorWithErrors( n, min, max, caller, name ) { - if ( n < min || n > max || n != truncate(n) ) { - raise( caller, ( name || 'decimal places' ) + - ( n < min || n > max ? ' out of range' : ' not an integer' ), n ); - } - - return true; - } - - - /* - * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP. - * Called by minus, plus and times. - */ - function normalise( n, c, e ) { - var i = 1, - j = c.length; - - // Remove trailing zeros. - for ( ; !c[--j]; c.pop() ); - - // Calculate the base 10 exponent. First get the number of digits of c[0]. - for ( j = c[0]; j >= 10; j /= 10, i++ ); - - // Overflow? - if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) { - - // Infinity. - n.c = n.e = null; - - // Underflow? - } else if ( e < MIN_EXP ) { - - // Zero. - n.c = [ n.e = 0 ]; - } else { - n.e = e; - n.c = c; - } - - return n; - } - - - // Handle values that fail the validity test in BigNumber. - parseNumeric = (function () { -// var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, - var basePrefix = /^(-?)0([xbo])/i, - dotAfter = /^([^.]+)\.$/, - dotBefore = /^\.([^.]+)$/, - isInfinityOrNaN = /^-?(Infinity|NaN)$/, -// whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g; - whitespaceOrPlus = /^\s*\+[\w.]|^\s+|\s+$/g; - - return function ( x, str, num, b ) { - var base, - s = num ? str : str.replace( whitespaceOrPlus, '' ); - - // No exception on ±Infinity or NaN. - if ( isInfinityOrNaN.test(s) ) { - x.s = isNaN(s) ? null : s < 0 ? -1 : 1; - } else { - if ( !num ) { - - // basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i - s = s.replace( basePrefix, function ( m, p1, p2 ) { - base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8; - return !b || b == base ? p1 : m; - }); - - if (b) { - base = b; - - // E.g. '1.' to '1', '.1' to '0.1' - s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' ); - } - - if ( str != s ) return new BigNumber( s, base ); - } - - // 'new BigNumber() not a number: {n}' - // 'new BigNumber() not a base {b} number: {n}' - if (ERRORS) raise( id, 'not a' + ( b ? ' base ' + b : '' ) + ' number', str ); - x.s = null; - } - - x.c = x.e = null; - id = 0; - } - })(); - - - // Throw a BigNumber Error. - function raise( caller, msg, val ) { - var error = new Error( [ - 'new BigNumber', // 0 - 'cmp', // 1 - 'config', // 2 - 'div', // 3 - 'divToInt', // 4 - 'eq', // 5 - 'gt', // 6 - 'gte', // 7 - 'lt', // 8 - 'lte', // 9 - 'minus', // 10 - 'mod', // 11 - 'plus', // 12 - 'precision', // 13 - 'random', // 14 - 'round', // 15 - 'shift', // 16 - 'times', // 17 - 'toDigits', // 18 - 'toExponential', // 19 - 'toFixed', // 20 - 'toFormat', // 21 - 'toFraction', // 22 - 'pow', // 23 - 'toPrecision', // 24 - 'toString', // 25 - 'BigNumber' // 26 - ][caller] + '() ' + msg + ': ' + val ); - - error.name = 'BigNumber Error'; - id = 0; - throw error; - } - - - /* - * Round x to sd significant digits using rounding mode rm. Check for over/under-flow. - * If r is truthy, it is known that there are more digits after the rounding digit. - */ - function round( x, sd, rm, r ) { - var d, i, j, k, n, ni, rd, - xc = x.c, - pows10 = POWS_TEN; - - // if x is not Infinity or NaN... - if (xc) { - - // rd is the rounding digit, i.e. the digit after the digit that may be rounded up. - // n is a base 1e14 number, the value of the element of array x.c containing rd. - // ni is the index of n within x.c. - // d is the number of digits of n. - // i is the index of rd within n including leading zeros. - // j is the actual index of rd within n (if < 0, rd is a leading zero). - out: { - - // Get the number of digits of the first element of xc. - for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ ); - i = sd - d; - - // If the rounding digit is in the first element of xc... - if ( i < 0 ) { - i += LOG_BASE; - j = sd; - n = xc[ ni = 0 ]; - - // Get the rounding digit at index j of n. - rd = n / pows10[ d - j - 1 ] % 10 | 0; - } else { - ni = mathceil( ( i + 1 ) / LOG_BASE ); - - if ( ni >= xc.length ) { - - if (r) { - - // Needed by sqrt. - for ( ; xc.length <= ni; xc.push(0) ); - n = rd = 0; - d = 1; - i %= LOG_BASE; - j = i - LOG_BASE + 1; - } else { - break out; - } - } else { - n = k = xc[ni]; - - // Get the number of digits of n. - for ( d = 1; k >= 10; k /= 10, d++ ); - - // Get the index of rd within n. - i %= LOG_BASE; - - // Get the index of rd within n, adjusted for leading zeros. - // The number of leading zeros of n is given by LOG_BASE - d. - j = i - LOG_BASE + d; - - // Get the rounding digit at index j of n. - rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0; - } - } - - r = r || sd < 0 || - - // Are there any non-zero digits after the rounding digit? - // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right - // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714. - xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] ); - - r = rm < 4 - ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) - : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 && - - // Check whether the digit to the left of the rounding digit is odd. - ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 || - rm == ( x.s < 0 ? 8 : 7 ) ); - - if ( sd < 1 || !xc[0] ) { - xc.length = 0; - - if (r) { - - // Convert sd to decimal places. - sd -= x.e + 1; - - // 1, 0.1, 0.01, 0.001, 0.0001 etc. - xc[0] = pows10[ sd % LOG_BASE ]; - x.e = -sd || 0; - } else { - - // Zero. - xc[0] = x.e = 0; - } - - return x; - } - - // Remove excess digits. - if ( i == 0 ) { - xc.length = ni; - k = 1; - ni--; - } else { - xc.length = ni + 1; - k = pows10[ LOG_BASE - i ]; - - // E.g. 56700 becomes 56000 if 7 is the rounding digit. - // j > 0 means i > number of leading zeros of n. - xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0; - } - - // Round up? - if (r) { - - for ( ; ; ) { - - // If the digit to be rounded up is in the first element of xc... - if ( ni == 0 ) { - - // i will be the length of xc[0] before k is added. - for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ ); - j = xc[0] += k; - for ( k = 1; j >= 10; j /= 10, k++ ); - - // if i != k the length has increased. - if ( i != k ) { - x.e++; - if ( xc[0] == BASE ) xc[0] = 1; - } - - break; - } else { - xc[ni] += k; - if ( xc[ni] != BASE ) break; - xc[ni--] = 0; - k = 1; - } - } - } - - // Remove trailing zeros. - for ( i = xc.length; xc[--i] === 0; xc.pop() ); - } - - // Overflow? Infinity. - if ( x.e > MAX_EXP ) { - x.c = x.e = null; - - // Underflow? Zero. - } else if ( x.e < MIN_EXP ) { - x.c = [ x.e = 0 ]; - } - } - - return x; - } - - - // PROTOTYPE/INSTANCE METHODS - - - /* - * Return a new BigNumber whose value is the absolute value of this BigNumber. - */ - P.absoluteValue = P.abs = function () { - var x = new BigNumber(this); - if ( x.s < 0 ) x.s = 1; - return x; - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole - * number in the direction of Infinity. - */ - P.ceil = function () { - return round( new BigNumber(this), this.e + 1, 2 ); - }; - - - /* - * Return - * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b), - * -1 if the value of this BigNumber is less than the value of BigNumber(y, b), - * 0 if they have the same value, - * or null if the value of either is NaN. - */ - P.comparedTo = P.cmp = function ( y, b ) { - id = 1; - return compare( this, new BigNumber( y, b ) ); - }; - - - /* - * Return the number of decimal places of the value of this BigNumber, or null if the value - * of this BigNumber is ±Infinity or NaN. - */ - P.decimalPlaces = P.dp = function () { - var n, v, - c = this.c; - - if ( !c ) return null; - n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE; - - // Subtract the number of trailing zeros of the last number. - if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- ); - if ( n < 0 ) n = 0; - - return n; - }; - - - /* - * n / 0 = I - * n / N = N - * n / I = 0 - * 0 / n = 0 - * 0 / 0 = N - * 0 / N = N - * 0 / I = 0 - * N / n = N - * N / 0 = N - * N / N = N - * N / I = N - * I / n = I - * I / 0 = I - * I / N = N - * I / I = N - * - * Return a new BigNumber whose value is the value of this BigNumber divided by the value of - * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE. - */ - P.dividedBy = P.div = function ( y, b ) { - id = 3; - return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE ); - }; - - - /* - * Return a new BigNumber whose value is the integer part of dividing the value of this - * BigNumber by the value of BigNumber(y, b). - */ - P.dividedToIntegerBy = P.divToInt = function ( y, b ) { - id = 4; - return div( this, new BigNumber( y, b ), 0, 1 ); - }; - - - /* - * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b), - * otherwise returns false. - */ - P.equals = P.eq = function ( y, b ) { - id = 5; - return compare( this, new BigNumber( y, b ) ) === 0; - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole - * number in the direction of -Infinity. - */ - P.floor = function () { - return round( new BigNumber(this), this.e + 1, 3 ); - }; - - - /* - * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b), - * otherwise returns false. - */ - P.greaterThan = P.gt = function ( y, b ) { - id = 6; - return compare( this, new BigNumber( y, b ) ) > 0; - }; - - - /* - * Return true if the value of this BigNumber is greater than or equal to the value of - * BigNumber(y, b), otherwise returns false. - */ - P.greaterThanOrEqualTo = P.gte = function ( y, b ) { - id = 7; - return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0; - - }; - - - /* - * Return true if the value of this BigNumber is a finite number, otherwise returns false. - */ - P.isFinite = function () { - return !!this.c; - }; - - - /* - * Return true if the value of this BigNumber is an integer, otherwise return false. - */ - P.isInteger = P.isInt = function () { - return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2; - }; - - - /* - * Return true if the value of this BigNumber is NaN, otherwise returns false. - */ - P.isNaN = function () { - return !this.s; - }; - - - /* - * Return true if the value of this BigNumber is negative, otherwise returns false. - */ - P.isNegative = P.isNeg = function () { - return this.s < 0; - }; - - - /* - * Return true if the value of this BigNumber is 0 or -0, otherwise returns false. - */ - P.isZero = function () { - return !!this.c && this.c[0] == 0; - }; - - - /* - * Return true if the value of this BigNumber is less than the value of BigNumber(y, b), - * otherwise returns false. - */ - P.lessThan = P.lt = function ( y, b ) { - id = 8; - return compare( this, new BigNumber( y, b ) ) < 0; - }; - - - /* - * Return true if the value of this BigNumber is less than or equal to the value of - * BigNumber(y, b), otherwise returns false. - */ - P.lessThanOrEqualTo = P.lte = function ( y, b ) { - id = 9; - return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0; - }; - - - /* - * n - 0 = n - * n - N = N - * n - I = -I - * 0 - n = -n - * 0 - 0 = 0 - * 0 - N = N - * 0 - I = -I - * N - n = N - * N - 0 = N - * N - N = N - * N - I = N - * I - n = I - * I - 0 = I - * I - N = N - * I - I = N - * - * Return a new BigNumber whose value is the value of this BigNumber minus the value of - * BigNumber(y, b). - */ - P.minus = P.sub = function ( y, b ) { - var i, j, t, xLTy, - x = this, - a = x.s; - - id = 10; - y = new BigNumber( y, b ); - b = y.s; - - // Either NaN? - if ( !a || !b ) return new BigNumber(NaN); - - // Signs differ? - if ( a != b ) { - y.s = -b; - return x.plus(y); - } - - var xe = x.e / LOG_BASE, - ye = y.e / LOG_BASE, - xc = x.c, - yc = y.c; - - if ( !xe || !ye ) { - - // Either Infinity? - if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN ); - - // Either zero? - if ( !xc[0] || !yc[0] ) { - - // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. - return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x : - - // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity - ROUNDING_MODE == 3 ? -0 : 0 ); - } - } - - xe = bitFloor(xe); - ye = bitFloor(ye); - xc = xc.slice(); - - // Determine which is the bigger number. - if ( a = xe - ye ) { - - if ( xLTy = a < 0 ) { - a = -a; - t = xc; - } else { - ye = xe; - t = yc; - } - - t.reverse(); - - // Prepend zeros to equalise exponents. - for ( b = a; b--; t.push(0) ); - t.reverse(); - } else { - - // Exponents equal. Check digit by digit. - j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b; - - for ( a = b = 0; b < j; b++ ) { - - if ( xc[b] != yc[b] ) { - xLTy = xc[b] < yc[b]; - break; - } - } - } - - // x < y? Point xc to the array of the bigger number. - if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s; - - b = ( j = yc.length ) - ( i = xc.length ); - - // Append zeros to xc if shorter. - // No need to add zeros to yc if shorter as subtract only needs to start at yc.length. - if ( b > 0 ) for ( ; b--; xc[i++] = 0 ); - b = BASE - 1; - - // Subtract yc from xc. - for ( ; j > a; ) { - - if ( xc[--j] < yc[j] ) { - for ( i = j; i && !xc[--i]; xc[i] = b ); - --xc[i]; - xc[j] += BASE; - } - - xc[j] -= yc[j]; - } - - // Remove leading zeros and adjust exponent accordingly. - for ( ; xc[0] == 0; xc.shift(), --ye ); - - // Zero? - if ( !xc[0] ) { - - // Following IEEE 754 (2008) 6.3, - // n - n = +0 but n - n = -0 when rounding towards -Infinity. - y.s = ROUNDING_MODE == 3 ? -1 : 1; - y.c = [ y.e = 0 ]; - return y; - } - - // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity - // for finite x and y. - return normalise( y, xc, ye ); - }; - - - /* - * n % 0 = N - * n % N = N - * n % I = n - * 0 % n = 0 - * -0 % n = -0 - * 0 % 0 = N - * 0 % N = N - * 0 % I = 0 - * N % n = N - * N % 0 = N - * N % N = N - * N % I = N - * I % n = N - * I % 0 = N - * I % N = N - * I % I = N - * - * Return a new BigNumber whose value is the value of this BigNumber modulo the value of - * BigNumber(y, b). The result depends on the value of MODULO_MODE. - */ - P.modulo = P.mod = function ( y, b ) { - var q, s, - x = this; - - id = 11; - y = new BigNumber( y, b ); - - // Return NaN if x is Infinity or NaN, or y is NaN or zero. - if ( !x.c || !y.s || y.c && !y.c[0] ) { - return new BigNumber(NaN); - - // Return x if y is Infinity or x is zero. - } else if ( !y.c || x.c && !x.c[0] ) { - return new BigNumber(x); - } - - if ( MODULO_MODE == 9 ) { - - // Euclidian division: q = sign(y) * floor(x / abs(y)) - // r = x - qy where 0 <= r < abs(y) - s = y.s; - y.s = 1; - q = div( x, y, 0, 3 ); - y.s = s; - q.s *= s; - } else { - q = div( x, y, 0, MODULO_MODE ); - } - - return x.minus( q.times(y) ); - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber negated, - * i.e. multiplied by -1. - */ - P.negated = P.neg = function () { - var x = new BigNumber(this); - x.s = -x.s || null; - return x; - }; - - - /* - * n + 0 = n - * n + N = N - * n + I = I - * 0 + n = n - * 0 + 0 = 0 - * 0 + N = N - * 0 + I = I - * N + n = N - * N + 0 = N - * N + N = N - * N + I = N - * I + n = I - * I + 0 = I - * I + N = N - * I + I = I - * - * Return a new BigNumber whose value is the value of this BigNumber plus the value of - * BigNumber(y, b). - */ - P.plus = P.add = function ( y, b ) { - var t, - x = this, - a = x.s; - - id = 12; - y = new BigNumber( y, b ); - b = y.s; - - // Either NaN? - if ( !a || !b ) return new BigNumber(NaN); - - // Signs differ? - if ( a != b ) { - y.s = -b; - return x.minus(y); - } - - var xe = x.e / LOG_BASE, - ye = y.e / LOG_BASE, - xc = x.c, - yc = y.c; - - if ( !xe || !ye ) { - - // Return ±Infinity if either ±Infinity. - if ( !xc || !yc ) return new BigNumber( a / 0 ); - - // Either zero? - // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. - if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 ); - } - - xe = bitFloor(xe); - ye = bitFloor(ye); - xc = xc.slice(); - - // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts. - if ( a = xe - ye ) { - if ( a > 0 ) { - ye = xe; - t = yc; - } else { - a = -a; - t = xc; - } - - t.reverse(); - for ( ; a--; t.push(0) ); - t.reverse(); - } - - a = xc.length; - b = yc.length; - - // Point xc to the longer array, and b to the shorter length. - if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a; - - // Only start adding at yc.length - 1 as the further digits of xc can be ignored. - for ( a = 0; b; ) { - a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0; - xc[b] %= BASE; - } - - if (a) { - xc.unshift(a); - ++ye; - } - - // No need to check for zero, as +x + +y != 0 && -x + -y != 0 - // ye = MAX_EXP + 1 possible - return normalise( y, xc, ye ); - }; - - - /* - * Return the number of significant digits of the value of this BigNumber. - * - * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0. - */ - P.precision = P.sd = function (z) { - var n, v, - x = this, - c = x.c; - - // 'precision() argument not a boolean or binary digit: {z}' - if ( z != null && z !== !!z && z !== 1 && z !== 0 ) { - if (ERRORS) raise( 13, 'argument' + notBool, z ); - if ( z != !!z ) z = null; - } - - if ( !c ) return null; - v = c.length - 1; - n = v * LOG_BASE + 1; - - if ( v = c[v] ) { - - // Subtract the number of trailing zeros of the last element. - for ( ; v % 10 == 0; v /= 10, n-- ); - - // Add the number of digits of the first element. - for ( v = c[0]; v >= 10; v /= 10, n++ ); - } - - if ( z && x.e + 1 > n ) n = x.e + 1; - - return n; - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of - * dp decimal places using rounding mode rm, or to 0 and ROUNDING_MODE respectively if - * omitted. - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'round() decimal places out of range: {dp}' - * 'round() decimal places not an integer: {dp}' - * 'round() rounding mode not an integer: {rm}' - * 'round() rounding mode out of range: {rm}' - */ - P.round = function ( dp, rm ) { - var n = new BigNumber(this); - - if ( dp == null || isValidInt( dp, 0, MAX, 15 ) ) { - round( n, ~~dp + this.e + 1, rm == null || - !isValidInt( rm, 0, 8, 15, roundingMode ) ? ROUNDING_MODE : rm | 0 ); - } - - return n; - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber shifted by k places - * (powers of 10). Shift to the right if n > 0, and to the left if n < 0. - * - * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. - * - * If k is out of range and ERRORS is false, the result will be ±0 if k < 0, or ±Infinity - * otherwise. - * - * 'shift() argument not an integer: {k}' - * 'shift() argument out of range: {k}' - */ - P.shift = function (k) { - var n = this; - return isValidInt( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 16, 'argument' ) - - // k < 1e+21, or truncate(k) will produce exponential notation. - ? n.times( '1e' + truncate(k) ) - : new BigNumber( n.c && n.c[0] && ( k < -MAX_SAFE_INTEGER || k > MAX_SAFE_INTEGER ) - ? n.s * ( k < 0 ? 0 : 1 / 0 ) - : n ); - }; - - - /* - * sqrt(-n) = N - * sqrt( N) = N - * sqrt(-I) = N - * sqrt( I) = I - * sqrt( 0) = 0 - * sqrt(-0) = -0 - * - * Return a new BigNumber whose value is the square root of the value of this BigNumber, - * rounded according to DECIMAL_PLACES and ROUNDING_MODE. - */ - P.squareRoot = P.sqrt = function () { - var m, n, r, rep, t, - x = this, - c = x.c, - s = x.s, - e = x.e, - dp = DECIMAL_PLACES + 4, - half = new BigNumber('0.5'); - - // Negative/NaN/Infinity/zero? - if ( s !== 1 || !c || !c[0] ) { - return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 ); - } - - // Initial estimate. - s = Math.sqrt( +x ); - - // Math.sqrt underflow/overflow? - // Pass x to Math.sqrt as integer, then adjust the exponent of the result. - if ( s == 0 || s == 1 / 0 ) { - n = coeffToString(c); - if ( ( n.length + e ) % 2 == 0 ) n += '0'; - s = Math.sqrt(n); - e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 ); - - if ( s == 1 / 0 ) { - n = '1e' + e; - } else { - n = s.toExponential(); - n = n.slice( 0, n.indexOf('e') + 1 ) + e; - } - - r = new BigNumber(n); - } else { - r = new BigNumber( s + '' ); - } - - // Check for zero. - // r could be zero if MIN_EXP is changed after the this value was created. - // This would cause a division by zero (x/t) and hence Infinity below, which would cause - // coeffToString to throw. - if ( r.c[0] ) { - e = r.e; - s = e + dp; - if ( s < 3 ) s = 0; - - // Newton-Raphson iteration. - for ( ; ; ) { - t = r; - r = half.times( t.plus( div( x, t, dp, 1 ) ) ); - - if ( coeffToString( t.c ).slice( 0, s ) === ( n = - coeffToString( r.c ) ).slice( 0, s ) ) { - - // The exponent of r may here be one less than the final result exponent, - // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits - // are indexed correctly. - if ( r.e < e ) --s; - n = n.slice( s - 3, s + 1 ); - - // The 4th rounding digit may be in error by -1 so if the 4 rounding digits - // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the - // iteration. - if ( n == '9999' || !rep && n == '4999' ) { - - // On the first iteration only, check to see if rounding up gives the - // exact result as the nines may infinitely repeat. - if ( !rep ) { - round( t, t.e + DECIMAL_PLACES + 2, 0 ); - - if ( t.times(t).eq(x) ) { - r = t; - break; - } - } - - dp += 4; - s += 4; - rep = 1; - } else { - - // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact - // result. If not, then there are further digits and m will be truthy. - if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) { - - // Truncate to the first rounding digit. - round( r, r.e + DECIMAL_PLACES + 2, 1 ); - m = !r.times(r).eq(x); - } - - break; - } - } - } - } - - return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m ); - }; - - - /* - * n * 0 = 0 - * n * N = N - * n * I = I - * 0 * n = 0 - * 0 * 0 = 0 - * 0 * N = N - * 0 * I = N - * N * n = N - * N * 0 = N - * N * N = N - * N * I = N - * I * n = I - * I * 0 = N - * I * N = N - * I * I = I - * - * Return a new BigNumber whose value is the value of this BigNumber times the value of - * BigNumber(y, b). - */ - P.times = P.mul = function ( y, b ) { - var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc, - base, sqrtBase, - x = this, - xc = x.c, - yc = ( id = 17, y = new BigNumber( y, b ) ).c; - - // Either NaN, ±Infinity or ±0? - if ( !xc || !yc || !xc[0] || !yc[0] ) { - - // Return NaN if either is NaN, or one is 0 and the other is Infinity. - if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) { - y.c = y.e = y.s = null; - } else { - y.s *= x.s; - - // Return ±Infinity if either is ±Infinity. - if ( !xc || !yc ) { - y.c = y.e = null; - - // Return ±0 if either is ±0. - } else { - y.c = [0]; - y.e = 0; - } - } - - return y; - } - - e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE ); - y.s *= x.s; - xcL = xc.length; - ycL = yc.length; - - // Ensure xc points to longer array and xcL to its length. - if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i; - - // Initialise the result array with zeros. - for ( i = xcL + ycL, zc = []; i--; zc.push(0) ); - - base = BASE; - sqrtBase = SQRT_BASE; - - for ( i = ycL; --i >= 0; ) { - c = 0; - ylo = yc[i] % sqrtBase; - yhi = yc[i] / sqrtBase | 0; - - for ( k = xcL, j = i + k; j > i; ) { - xlo = xc[--k] % sqrtBase; - xhi = xc[k] / sqrtBase | 0; - m = yhi * xlo + xhi * ylo; - xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c; - c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi; - zc[j--] = xlo % base; - } - - zc[j] = c; - } - - if (c) { - ++e; - } else { - zc.shift(); - } - - return normalise( y, zc, e ); - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of - * sd significant digits using rounding mode rm, or ROUNDING_MODE if rm is omitted. - * - * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toDigits() precision out of range: {sd}' - * 'toDigits() precision not an integer: {sd}' - * 'toDigits() rounding mode not an integer: {rm}' - * 'toDigits() rounding mode out of range: {rm}' - */ - P.toDigits = function ( sd, rm ) { - var n = new BigNumber(this); - sd = sd == null || !isValidInt( sd, 1, MAX, 18, 'precision' ) ? null : sd | 0; - rm = rm == null || !isValidInt( rm, 0, 8, 18, roundingMode ) ? ROUNDING_MODE : rm | 0; - return sd ? round( n, sd, rm ) : n; - }; - - - /* - * Return a string representing the value of this BigNumber in exponential notation and - * rounded using ROUNDING_MODE to dp fixed decimal places. - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toExponential() decimal places not an integer: {dp}' - * 'toExponential() decimal places out of range: {dp}' - * 'toExponential() rounding mode not an integer: {rm}' - * 'toExponential() rounding mode out of range: {rm}' - */ - P.toExponential = function ( dp, rm ) { - return format( this, - dp != null && isValidInt( dp, 0, MAX, 19 ) ? ~~dp + 1 : null, rm, 19 ); - }; - - - /* - * Return a string representing the value of this BigNumber in fixed-point notation rounding - * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted. - * - * Note: as with JavaScript's number type, (-0).toFixed(0) is '0', - * but e.g. (-0.00001).toFixed(0) is '-0'. - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toFixed() decimal places not an integer: {dp}' - * 'toFixed() decimal places out of range: {dp}' - * 'toFixed() rounding mode not an integer: {rm}' - * 'toFixed() rounding mode out of range: {rm}' - */ - P.toFixed = function ( dp, rm ) { - return format( this, dp != null && isValidInt( dp, 0, MAX, 20 ) - ? ~~dp + this.e + 1 : null, rm, 20 ); - }; - - - /* - * Return a string representing the value of this BigNumber in fixed-point notation rounded - * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties - * of the FORMAT object (see BigNumber.config). - * - * FORMAT = { - * decimalSeparator : '.', - * groupSeparator : ',', - * groupSize : 3, - * secondaryGroupSize : 0, - * fractionGroupSeparator : '\xA0', // non-breaking space - * fractionGroupSize : 0 - * }; - * - * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toFormat() decimal places not an integer: {dp}' - * 'toFormat() decimal places out of range: {dp}' - * 'toFormat() rounding mode not an integer: {rm}' - * 'toFormat() rounding mode out of range: {rm}' - */ - P.toFormat = function ( dp, rm ) { - var str = format( this, dp != null && isValidInt( dp, 0, MAX, 21 ) - ? ~~dp + this.e + 1 : null, rm, 21 ); - - if ( this.c ) { - var i, - arr = str.split('.'), - g1 = +FORMAT.groupSize, - g2 = +FORMAT.secondaryGroupSize, - groupSeparator = FORMAT.groupSeparator, - intPart = arr[0], - fractionPart = arr[1], - isNeg = this.s < 0, - intDigits = isNeg ? intPart.slice(1) : intPart, - len = intDigits.length; - - if (g2) i = g1, g1 = g2, g2 = i, len -= i; - - if ( g1 > 0 && len > 0 ) { - i = len % g1 || g1; - intPart = intDigits.substr( 0, i ); - - for ( ; i < len; i += g1 ) { - intPart += groupSeparator + intDigits.substr( i, g1 ); - } - - if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i); - if (isNeg) intPart = '-' + intPart; - } - - str = fractionPart - ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize ) - ? fractionPart.replace( new RegExp( '\\d{' + g2 + '}\\B', 'g' ), - '$&' + FORMAT.fractionGroupSeparator ) - : fractionPart ) - : intPart; - } - - return str; - }; - - - /* - * Return a string array representing the value of this BigNumber as a simple fraction with - * an integer numerator and an integer denominator. The denominator will be a positive - * non-zero value less than or equal to the specified maximum denominator. If a maximum - * denominator is not specified, the denominator will be the lowest value necessary to - * represent the number exactly. - * - * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator. - * - * 'toFraction() max denominator not an integer: {md}' - * 'toFraction() max denominator out of range: {md}' - */ - P.toFraction = function (md) { - var arr, d0, d2, e, exp, n, n0, q, s, - k = ERRORS, - x = this, - xc = x.c, - d = new BigNumber(ONE), - n1 = d0 = new BigNumber(ONE), - d1 = n0 = new BigNumber(ONE); - - if ( md != null ) { - ERRORS = false; - n = new BigNumber(md); - ERRORS = k; - - if ( !( k = n.isInt() ) || n.lt(ONE) ) { - - if (ERRORS) { - raise( 22, - 'max denominator ' + ( k ? 'out of range' : 'not an integer' ), md ); - } - - // ERRORS is false: - // If md is a finite non-integer >= 1, round it to an integer and use it. - md = !k && n.c && round( n, n.e + 1, 1 ).gte(ONE) ? n : null; - } - } - - if ( !xc ) return x.toString(); - s = coeffToString(xc); - - // Determine initial denominator. - // d is a power of 10 and the minimum max denominator that specifies the value exactly. - e = d.e = s.length - x.e - 1; - d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ]; - md = !md || n.cmp(d) > 0 ? ( e > 0 ? d : n1 ) : n; - - exp = MAX_EXP; - MAX_EXP = 1 / 0; - n = new BigNumber(s); - - // n0 = d1 = 0 - n0.c[0] = 0; - - for ( ; ; ) { - q = div( n, d, 0, 1 ); - d2 = d0.plus( q.times(d1) ); - if ( d2.cmp(md) == 1 ) break; - d0 = d1; - d1 = d2; - n1 = n0.plus( q.times( d2 = n1 ) ); - n0 = d2; - d = n.minus( q.times( d2 = d ) ); - n = d2; - } - - d2 = div( md.minus(d0), d1, 0, 1 ); - n0 = n0.plus( d2.times(n1) ); - d0 = d0.plus( d2.times(d1) ); - n0.s = n1.s = x.s; - e *= 2; - - // Determine which fraction is closer to x, n0/d0 or n1/d1 - arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().cmp( - div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1 - ? [ n1.toString(), d1.toString() ] - : [ n0.toString(), d0.toString() ]; - - MAX_EXP = exp; - return arr; - }; - - - /* - * Return the value of this BigNumber converted to a number primitive. - */ - P.toNumber = function () { - var x = this; - - // Ensure zero has correct sign. - return +x || ( x.s ? x.s * 0 : NaN ); - }; - - - /* - * Return a BigNumber whose value is the value of this BigNumber raised to the power n. - * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE. - * If POW_PRECISION is not 0, round to POW_PRECISION using ROUNDING_MODE. - * - * n {number} Integer, -9007199254740992 to 9007199254740992 inclusive. - * (Performs 54 loop iterations for n of 9007199254740992.) - * - * 'pow() exponent not an integer: {n}' - * 'pow() exponent out of range: {n}' - */ - P.toPower = P.pow = function (n) { - var k, y, - i = mathfloor( n < 0 ? -n : +n ), - x = this; - - // Pass ±Infinity to Math.pow if exponent is out of range. - if ( !isValidInt( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 23, 'exponent' ) && - ( !isFinite(n) || i > MAX_SAFE_INTEGER && ( n /= 0 ) || - parseFloat(n) != n && !( n = NaN ) ) ) { - return new BigNumber( Math.pow( +x, n ) ); - } - - // Truncating each coefficient array to a length of k after each multiplication equates - // to truncating significant digits to POW_PRECISION + [28, 41], i.e. there will be a - // minimum of 28 guard digits retained. (Using + 1.5 would give [9, 21] guard digits.) - k = POW_PRECISION ? mathceil( POW_PRECISION / LOG_BASE + 2 ) : 0; - y = new BigNumber(ONE); - - for ( ; ; ) { - - if ( i % 2 ) { - y = y.times(x); - if ( !y.c ) break; - if ( k && y.c.length > k ) y.c.length = k; - } - - i = mathfloor( i / 2 ); - if ( !i ) break; - - x = x.times(x); - if ( k && x.c && x.c.length > k ) x.c.length = k; - } - - if ( n < 0 ) y = ONE.div(y); - return k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y; - }; - - - /* - * Return a string representing the value of this BigNumber rounded to sd significant digits - * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits - * necessary to represent the integer part of the value in fixed-point notation, then use - * exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toPrecision() precision not an integer: {sd}' - * 'toPrecision() precision out of range: {sd}' - * 'toPrecision() rounding mode not an integer: {rm}' - * 'toPrecision() rounding mode out of range: {rm}' - */ - P.toPrecision = function ( sd, rm ) { - return format( this, sd != null && isValidInt( sd, 1, MAX, 24, 'precision' ) - ? sd | 0 : null, rm, 24 ); - }; - - - /* - * Return a string representing the value of this BigNumber in base b, or base 10 if b is - * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and - * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent - * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than - * TO_EXP_NEG, return exponential notation. - * - * [b] {number} Integer, 2 to 64 inclusive. - * - * 'toString() base not an integer: {b}' - * 'toString() base out of range: {b}' - */ - P.toString = function (b) { - var str, - n = this, - s = n.s, - e = n.e; - - // Infinity or NaN? - if ( e === null ) { - - if (s) { - str = 'Infinity'; - if ( s < 0 ) str = '-' + str; - } else { - str = 'NaN'; - } - } else { - str = coeffToString( n.c ); - - if ( b == null || !isValidInt( b, 2, 64, 25, 'base' ) ) { - str = e <= TO_EXP_NEG || e >= TO_EXP_POS - ? toExponential( str, e ) - : toFixedPoint( str, e ); - } else { - str = convertBase( toFixedPoint( str, e ), b | 0, 10, s ); - } - - if ( s < 0 && n.c[0] ) str = '-' + str; - } - - return str; - }; - - - /* - * Return a new BigNumber whose value is the value of this BigNumber truncated to a whole - * number. - */ - P.truncated = P.trunc = function () { - return round( new BigNumber(this), this.e + 1, 1 ); - }; - - - - /* - * Return as toString, but do not accept a base argument. - */ - P.valueOf = P.toJSON = function () { - return this.toString(); - }; - - - // Aliases for BigDecimal methods. - //P.add = P.plus; // P.add included above - //P.subtract = P.minus; // P.sub included above - //P.multiply = P.times; // P.mul included above - //P.divide = P.div; - //P.remainder = P.mod; - //P.compareTo = P.cmp; - //P.negate = P.neg; - - - if ( configObj != null ) BigNumber.config(configObj); - - return BigNumber; - } - - - // PRIVATE HELPER FUNCTIONS - - - function bitFloor(n) { - var i = n | 0; - return n > 0 || n === i ? i : i - 1; - } - - - // Return a coefficient array as a string of base 10 digits. - function coeffToString(a) { - var s, z, - i = 1, - j = a.length, - r = a[0] + ''; - - for ( ; i < j; ) { - s = a[i++] + ''; - z = LOG_BASE - s.length; - for ( ; z--; s = '0' + s ); - r += s; - } - - // Determine trailing zeros. - for ( j = r.length; r.charCodeAt(--j) === 48; ); - return r.slice( 0, j + 1 || 1 ); - } - - - // Compare the value of BigNumbers x and y. - function compare( x, y ) { - var a, b, - xc = x.c, - yc = y.c, - i = x.s, - j = y.s, - k = x.e, - l = y.e; - - // Either NaN? - if ( !i || !j ) return null; - - a = xc && !xc[0]; - b = yc && !yc[0]; - - // Either zero? - if ( a || b ) return a ? b ? 0 : -j : i; - - // Signs differ? - if ( i != j ) return i; - - a = i < 0; - b = k == l; - - // Either Infinity? - if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1; - - // Compare exponents. - if ( !b ) return k > l ^ a ? 1 : -1; - - j = ( k = xc.length ) < ( l = yc.length ) ? k : l; - - // Compare digit by digit. - for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1; - - // Compare lengths. - return k == l ? 0 : k > l ^ a ? 1 : -1; - } - - - /* - * Return true if n is a valid number in range, otherwise false. - * Use for argument validation when ERRORS is false. - * Note: parseInt('1e+1') == 1 but parseFloat('1e+1') == 10. - */ - function intValidatorNoErrors( n, min, max ) { - return ( n = truncate(n) ) >= min && n <= max; - } - - - function isArray(obj) { - return Object.prototype.toString.call(obj) == '[object Array]'; - } - - - /* - * Convert string of baseIn to an array of numbers of baseOut. - * Eg. convertBase('255', 10, 16) returns [15, 15]. - * Eg. convertBase('ff', 16, 10) returns [2, 5, 5]. - */ - function toBaseOut( str, baseIn, baseOut ) { - var j, - arr = [0], - arrL, - i = 0, - len = str.length; - - for ( ; i < len; ) { - for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn ); - arr[ j = 0 ] += ALPHABET.indexOf( str.charAt( i++ ) ); - - for ( ; j < arr.length; j++ ) { - - if ( arr[j] > baseOut - 1 ) { - if ( arr[j + 1] == null ) arr[j + 1] = 0; - arr[j + 1] += arr[j] / baseOut | 0; - arr[j] %= baseOut; - } - } - } - - return arr.reverse(); - } - - - function toExponential( str, e ) { - return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) + - ( e < 0 ? 'e' : 'e+' ) + e; - } - - - function toFixedPoint( str, e ) { - var len, z; - - // Negative exponent? - if ( e < 0 ) { - - // Prepend zeros. - for ( z = '0.'; ++e; z += '0' ); - str = z + str; - - // Positive exponent - } else { - len = str.length; - - // Append zeros. - if ( ++e > len ) { - for ( z = '0', e -= len; --e; z += '0' ); - str += z; - } else if ( e < len ) { - str = str.slice( 0, e ) + '.' + str.slice(e); - } - } - - return str; - } - - - function truncate(n) { - n = parseFloat(n); - return n < 0 ? mathceil(n) : mathfloor(n); - } - - - // EXPORT - - - BigNumber = another(); - - // AMD. - if ( typeof define == 'function' && define.amd ) { - define( function () { return BigNumber; } ); - - // Node and other environments that support module.exports. - } else if ( typeof module != 'undefined' && module.exports ) { - module.exports = BigNumber; - if ( !crypto ) try { crypto = require('crypto'); } catch (e) {} - - // Browser. - } else { - global.BigNumber = BigNumber; - } -})(this); - -},{"crypto":1}],"natspec":[function(require,module,exports){ -/* - This file is part of natspec.js. - - natspec.js 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. - - natspec.js 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 natspec.js. If not, see . -*/ -/** @file natspec.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var abi = require('./node_modules/ethereum.js/lib/abi.js'); - -/** - * This object should be used to evaluate natspec expression - * It has one method evaluateExpression which shoul be used - */ -var natspec = (function () { - /// Helper method - /// Should be called to copy values from object to global context - var copyToContext = function (obj, context) { - Object.keys(obj).forEach(function (key) { - context[key] = obj[key]; - }); - } - - /// generate codes, which will be evaluated - var generateCode = function (obj) { - return Object.keys(obj).reduce(function (acc, key) { - return acc + "var " + key + " = context['" + key + "'];\n"; - }, ""); - }; - - /// Helper method - /// Should be called to get method with given name from the abi - /// @param contract's abi - /// @param name of the method that we are looking for - var getMethodWithName = function(abi, name) { - return abi.filter(function (method) { - return method.name === name; - })[0]; - }; - - /// Function called to get all contract method input variables - /// @returns hashmap with all contract's method input variables - var getMethodInputParams = function (method, transaction) { - // do it with output formatter (cause we have to decode) - var params = abi.formatOutput(method.inputs, '0x' + transaction.params[0].data.slice(10)); - - return method.inputs.reduce(function (acc, current, index) { - acc[current.name] = params[index]; - return acc; - }, {}); - }; - - /// Should be called to evaluate expression - var mapExpressionsToEvaluate = function (expression, cb) { - var evaluatedExpression = ""; - - // match everything in `` quotes - var pattern = /\`(?:\\.|[^`\\])*\`/gim - var match; - var lastIndex = 0; - while ((match = pattern.exec(expression)) !== null) { - var startIndex = pattern.lastIndex - match[0].length; - var toEval = match[0].slice(1, match[0].length - 1); - evaluatedExpression += expression.slice(lastIndex, startIndex); - var evaluatedPart = cb(toEval); - evaluatedExpression += evaluatedPart; - lastIndex = pattern.lastIndex; - } - - evaluatedExpression += expression.slice(lastIndex); - - return evaluatedExpression; - }; - - /// Should be called to evaluate single expression - /// Is internally using javascript's 'eval' method - /// @param expression which should be evaluated - /// @param [call] object containing contract abi, transaction, called method - /// TODO: separate evaluation from getting input params, so as not to spoil 'evaluateExpression' function - var evaluateExpression = function (expression, call) { - //var self = this; - var context = {}; - - if (!!call) { - try { - var method = getMethodWithName(call.abi, call.method); - var params = getMethodInputParams(method, call.transaction); - copyToContext(params, context); - } - catch (err) { - return "Natspec evaluation failed, wrong input params"; - } - } - - var code = generateCode(context); - - var evaluatedExpression = mapExpressionsToEvaluate(expression, function (toEval) { - try { - var fn = new Function("context", code + "return " + toEval + ";"); - return fn(context).toString(); - } - catch (err) { - return 'undefined'; - } - }); - - return evaluatedExpression; - }; - - return { - evaluateExpression: evaluateExpression - }; - -})(); - -module.exports = natspec; - - -},{"./node_modules/ethereum.js/lib/abi.js":3}]},{},[]); diff --git a/ethutil/natspec/natspec_js.go b/ethutil/natspec/natspec_js.go new file mode 100644 index 000000000..7acaaee4f --- /dev/null +++ b/ethutil/natspec/natspec_js.go @@ -0,0 +1,3520 @@ +package natspec + +const natspecJS = `require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o. +*/ +/** @file abi.js + * @authors: + * Marek Kotewicz + * Gav Wood + * @date 2014 + */ + +var utils = require('./utils'); +var types = require('./types'); +var c = require('./const'); +var f = require('./formatters'); + +var displayTypeError = function (type) { + console.error('parser does not support type: ' + type); +}; + +/// This method should be called if we want to check if givent type is an array type +/// @returns true if it is, otherwise false +var arrayType = function (type) { + return type.slice(-2) === '[]'; +}; + +var dynamicTypeBytes = function (type, value) { + // TODO: decide what to do with array of strings + if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. + return f.formatInputInt(value.length); + return ""; +}; + +var inputTypes = types.inputTypes(); + +/// Formats input params to bytes +/// @param abi contract method inputs +/// @param array of params that will be formatted to bytes +/// @returns bytes representation of input params +var formatInput = function (inputs, params) { + var bytes = ""; + var toAppendConstant = ""; + var toAppendArrayContent = ""; + + /// first we iterate in search for dynamic + inputs.forEach(function (input, index) { + bytes += dynamicTypeBytes(input.type, params[index]); + }); + + inputs.forEach(function (input, i) { + /*jshint maxcomplexity:5 */ + var typeMatch = false; + for (var j = 0; j < inputTypes.length && !typeMatch; j++) { + typeMatch = inputTypes[j].type(inputs[i].type, params[i]); + } + if (!typeMatch) { + displayTypeError(inputs[i].type); + } + + var formatter = inputTypes[j - 1].format; + + if (arrayType(inputs[i].type)) + toAppendArrayContent += params[i].reduce(function (acc, curr) { + return acc + formatter(curr); + }, ""); + else if (inputs[i].type === 'string') + toAppendArrayContent += formatter(params[i]); + else + toAppendConstant += formatter(params[i]); + }); + + bytes += toAppendConstant + toAppendArrayContent; + + return bytes; +}; + +var dynamicBytesLength = function (type) { + if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. + return c.ETH_PADDING * 2; + return 0; +}; + +var outputTypes = types.outputTypes(); + +/// Formats output bytes back to param list +/// @param contract abi method outputs +/// @param bytes representtion of output +/// @returns array of output params +var formatOutput = function (outs, output) { + + output = output.slice(2); + var result = []; + var padding = c.ETH_PADDING * 2; + + var dynamicPartLength = outs.reduce(function (acc, curr) { + return acc + dynamicBytesLength(curr.type); + }, 0); + + var dynamicPart = output.slice(0, dynamicPartLength); + output = output.slice(dynamicPartLength); + + outs.forEach(function (out, i) { + /*jshint maxcomplexity:6 */ + var typeMatch = false; + for (var j = 0; j < outputTypes.length && !typeMatch; j++) { + typeMatch = outputTypes[j].type(outs[i].type); + } + + if (!typeMatch) { + displayTypeError(outs[i].type); + } + + var formatter = outputTypes[j - 1].format; + if (arrayType(outs[i].type)) { + var size = f.formatOutputUInt(dynamicPart.slice(0, padding)); + dynamicPart = dynamicPart.slice(padding); + var array = []; + for (var k = 0; k < size; k++) { + array.push(formatter(output.slice(0, padding))); + output = output.slice(padding); + } + result.push(array); + } + else if (types.prefixedType('string')(outs[i].type)) { + dynamicPart = dynamicPart.slice(padding); + result.push(formatter(output.slice(0, padding))); + output = output.slice(padding); + } else { + result.push(formatter(output.slice(0, padding))); + output = output.slice(padding); + } + }); + + return result; +}; + +/// @param json abi for contract +/// @returns input parser object for given json abi +/// TODO: refactor creating the parser, do not double logic from contract +var inputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + var displayName = utils.extractDisplayName(method.name); + var typeName = utils.extractTypeName(method.name); + + var impl = function () { + var params = Array.prototype.slice.call(arguments); + return formatInput(method.inputs, params); + }; + + if (parser[displayName] === undefined) { + parser[displayName] = impl; + } + + parser[displayName][typeName] = impl; + }); + + return parser; +}; + +/// @param json abi for contract +/// @returns output parser for given json abi +var outputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + + var displayName = utils.extractDisplayName(method.name); + var typeName = utils.extractTypeName(method.name); + + var impl = function (output) { + return formatOutput(method.outputs, output); + }; + + if (parser[displayName] === undefined) { + parser[displayName] = impl; + } + + parser[displayName][typeName] = impl; + }); + + return parser; +}; + +module.exports = { + inputParser: inputParser, + outputParser: outputParser, + formatInput: formatInput, + formatOutput: formatOutput +}; + +},{"./const":4,"./formatters":5,"./types":6,"./utils":7}],4:[function(require,module,exports){ +(function (process){ +/* + This file is part of ethereum.js. + + ethereum.js 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. + + ethereum.js 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 ethereum.js. If not, see . +*/ +/** @file const.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// required to define ETH_BIGNUMBER_ROUNDING_MODE +if (process.env.NODE_ENV !== 'build') { + var BigNumber = require('bignumber.js'); // jshint ignore:line +} + +var ETH_UNITS = [ + 'wei', + 'Kwei', + 'Mwei', + 'Gwei', + 'szabo', + 'finney', + 'ether', + 'grand', + 'Mether', + 'Gether', + 'Tether', + 'Pether', + 'Eether', + 'Zether', + 'Yether', + 'Nether', + 'Dether', + 'Vether', + 'Uether' +]; + +module.exports = { + ETH_PADDING: 32, + ETH_SIGNATURE_LENGTH: 4, + ETH_UNITS: ETH_UNITS, + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, + ETH_POLLING_TIMEOUT: 1000 +}; + + +}).call(this,require('_process')) +},{"_process":2,"bignumber.js":8}],5:[function(require,module,exports){ +(function (process){ +/* + This file is part of ethereum.js. + + ethereum.js 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. + + ethereum.js 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 ethereum.js. If not, see . +*/ +/** @file formatters.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +if (process.env.NODE_ENV !== 'build') { + var BigNumber = require('bignumber.js'); // jshint ignore:line +} + +var utils = require('./utils'); +var c = require('./const'); + +/// @param string string to be padded +/// @param number of characters that result string should have +/// @param sign, by default 0 +/// @returns right aligned string +var padLeft = function (string, chars, sign) { + return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; +}; + +/// Formats input value to byte representation of int +/// If value is negative, return it's two's complement +/// If the value is floating point, round it down +/// @returns right-aligned byte representation of int +var formatInputInt = function (value) { + /*jshint maxcomplexity:7 */ + var padding = c.ETH_PADDING * 2; + if (value instanceof BigNumber || typeof value === 'number') { + if (typeof value === 'number') + value = new BigNumber(value); + BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE); + value = value.round(); + + if (value.lessThan(0)) + value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1); + value = value.toString(16); + } + else if (value.indexOf('0x') === 0) + value = value.substr(2); + else if (typeof value === 'string') + value = formatInputInt(new BigNumber(value)); + else + value = (+value).toString(16); + return padLeft(value, padding); +}; + +/// Formats input value to byte representation of string +/// @returns left-algined byte representation of string +var formatInputString = function (value) { + return utils.fromAscii(value, c.ETH_PADDING).substr(2); +}; + +/// Formats input value to byte representation of bool +/// @returns right-aligned byte representation bool +var formatInputBool = function (value) { + return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0'); +}; + +/// Formats input value to byte representation of real +/// Values are multiplied by 2^m and encoded as integers +/// @returns byte representation of real +var formatInputReal = function (value) { + return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); +}; + + +/// Check if input value is negative +/// @param value is hex format +/// @returns true if it is negative, otherwise false +var signedIsNegative = function (value) { + return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; +}; + +/// Formats input right-aligned input bytes to int +/// @returns right-aligned input bytes formatted to int +var formatOutputInt = function (value) { + value = value || "0"; + // check if it's negative number + // it it is, return two's complement + if (signedIsNegative(value)) { + return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1); + } + return new BigNumber(value, 16); +}; + +/// Formats big right-aligned input bytes to uint +/// @returns right-aligned input bytes formatted to uint +var formatOutputUInt = function (value) { + value = value || "0"; + return new BigNumber(value, 16); +}; + +/// @returns input bytes formatted to real +var formatOutputReal = function (value) { + return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); +}; + +/// @returns input bytes formatted to ureal +var formatOutputUReal = function (value) { + return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); +}; + +/// @returns right-aligned input bytes formatted to hex +var formatOutputHash = function (value) { + return "0x" + value; +}; + +/// @returns right-aligned input bytes formatted to bool +var formatOutputBool = function (value) { + return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; +}; + +/// @returns left-aligned input bytes formatted to ascii string +var formatOutputString = function (value) { + return utils.toAscii(value); +}; + +/// @returns right-aligned input bytes formatted to address +var formatOutputAddress = function (value) { + return "0x" + value.slice(value.length - 40, value.length); +}; + + +module.exports = { + formatInputInt: formatInputInt, + formatInputString: formatInputString, + formatInputBool: formatInputBool, + formatInputReal: formatInputReal, + formatOutputInt: formatOutputInt, + formatOutputUInt: formatOutputUInt, + formatOutputReal: formatOutputReal, + formatOutputUReal: formatOutputUReal, + formatOutputHash: formatOutputHash, + formatOutputBool: formatOutputBool, + formatOutputString: formatOutputString, + formatOutputAddress: formatOutputAddress +}; + + +}).call(this,require('_process')) +},{"./const":4,"./utils":7,"_process":2,"bignumber.js":8}],6:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js 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. + + ethereum.js 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 ethereum.js. If not, see . +*/ +/** @file types.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var f = require('./formatters'); + +/// @param expected type prefix (string) +/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false +var prefixedType = function (prefix) { + return function (type) { + return type.indexOf(prefix) === 0; + }; +}; + +/// @param expected type name (string) +/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false +var namedType = function (name) { + return function (type) { + return name === type; + }; +}; + +/// Setups input formatters for solidity types +/// @returns an array of input formatters +var inputTypes = function () { + + return [ + { type: prefixedType('uint'), format: f.formatInputInt }, + { type: prefixedType('int'), format: f.formatInputInt }, + { type: prefixedType('hash'), format: f.formatInputInt }, + { type: prefixedType('string'), format: f.formatInputString }, + { type: prefixedType('real'), format: f.formatInputReal }, + { type: prefixedType('ureal'), format: f.formatInputReal }, + { type: namedType('address'), format: f.formatInputInt }, + { type: namedType('bool'), format: f.formatInputBool } + ]; +}; + +/// Setups output formaters for solidity types +/// @returns an array of output formatters +var outputTypes = function () { + + return [ + { type: prefixedType('uint'), format: f.formatOutputUInt }, + { type: prefixedType('int'), format: f.formatOutputInt }, + { type: prefixedType('hash'), format: f.formatOutputHash }, + { type: prefixedType('string'), format: f.formatOutputString }, + { type: prefixedType('real'), format: f.formatOutputReal }, + { type: prefixedType('ureal'), format: f.formatOutputUReal }, + { type: namedType('address'), format: f.formatOutputAddress }, + { type: namedType('bool'), format: f.formatOutputBool } + ]; +}; + +module.exports = { + prefixedType: prefixedType, + namedType: namedType, + inputTypes: inputTypes, + outputTypes: outputTypes +}; + + +},{"./formatters":5}],7:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js 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. + + ethereum.js 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 ethereum.js. If not, see . +*/ +/** @file utils.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var c = require('./const'); + +/// Finds first index of array element matching pattern +/// @param array +/// @param callback pattern +/// @returns index of element +var findIndex = function (array, callback) { + var end = false; + var i = 0; + for (; i < array.length && !end; i++) { + end = callback(array[i]); + } + return end ? i - 1 : -1; +}; + +/// @returns ascii string representation of hex value prefixed with 0x +var toAscii = function(hex) { +// Find termination + var str = ""; + var i = 0, l = hex.length; + if (hex.substring(0, 2) === '0x') { + i = 2; + } + for (; i < l; i+=2) { + var code = parseInt(hex.substr(i, 2), 16); + if (code === 0) { + break; + } + + str += String.fromCharCode(code); + } + + return str; +}; + +var toHex = function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; +}; + +/// @returns hex representation (prefixed by 0x) of ascii string +var fromAscii = function(str, pad) { + pad = pad === undefined ? 0 : pad; + var hex = toHex(str); + while (hex.length < pad*2) + hex += "00"; + return "0x" + hex; +}; + +/// @returns display name for function/event eg. multiply(uint256) -> multiply +var extractDisplayName = function (name) { + var length = name.indexOf('('); + return length !== -1 ? name.substr(0, length) : name; +}; + +/// @returns overloaded part of function/event name +var extractTypeName = function (name) { + /// TODO: make it invulnerable + var length = name.indexOf('('); + return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; +}; + +/// Filters all function from input abi +/// @returns abi array with filtered objects of type 'function' +var filterFunctions = function (json) { + return json.filter(function (current) { + return current.type === 'function'; + }); +}; + +/// Filters all events form input abi +/// @returns abi array with filtered objects of type 'event' +var filterEvents = function (json) { + return json.filter(function (current) { + return current.type === 'event'; + }); +}; + +/// used to transform value/string to eth string +/// TODO: use BigNumber.js to parse int +/// TODO: add tests for it! +var toEth = function (str) { + /*jshint maxcomplexity:7 */ + var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; + var unit = 0; + var units = c.ETH_UNITS; + while (val > 3000 && unit < units.length - 1) + { + val /= 1000; + unit++; + } + var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); + var replaceFunction = function($0, $1, $2) { + return $1 + ',' + $2; + }; + + while (true) { + var o = s; + s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction); + if (o === s) + break; + } + return s + ' ' + units[unit]; +}; + +module.exports = { + findIndex: findIndex, + toAscii: toAscii, + fromAscii: fromAscii, + extractDisplayName: extractDisplayName, + extractTypeName: extractTypeName, + filterFunctions: filterFunctions, + filterEvents: filterEvents, + toEth: toEth +}; + + +},{"./const":4}],8:[function(require,module,exports){ +/*! bignumber.js v2.0.3 https://github.com/MikeMcl/bignumber.js/LICENCE */ + +;(function (global) { + 'use strict'; + + /* + bignumber.js v2.0.3 + A JavaScript library for arbitrary-precision arithmetic. + https://github.com/MikeMcl/bignumber.js + Copyright (c) 2015 Michael Mclaughlin + MIT Expat Licence + */ + + + var BigNumber, crypto, parseNumeric, + isNumeric = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, + mathceil = Math.ceil, + mathfloor = Math.floor, + notBool = ' not a boolean or binary digit', + roundingMode = 'rounding mode', + tooManyDigits = 'number type has more than 15 significant digits', + ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_', + BASE = 1e14, + LOG_BASE = 14, + MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1 + // MAX_INT32 = 0x7fffffff, // 2^31 - 1 + POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], + SQRT_BASE = 1e7, + + /* + * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and + * the arguments to toExponential, toFixed, toFormat, and toPrecision, beyond which an + * exception is thrown (if ERRORS is true). + */ + MAX = 1E9; // 0 to MAX_INT32 + + + /* + * Create and return a BigNumber constructor. + */ + function another(configObj) { + var div, + + // id tracks the caller function, so its name can be included in error messages. + id = 0, + P = BigNumber.prototype, + ONE = new BigNumber(1), + + + /********************************* EDITABLE DEFAULTS **********************************/ + + + /* + * The default values below must be integers within the inclusive ranges stated. + * The values can also be changed at run-time using BigNumber.config. + */ + + // The maximum number of decimal places for operations involving division. + DECIMAL_PLACES = 20, // 0 to MAX + + /* + * The rounding mode used when rounding to the above decimal places, and when using + * toExponential, toFixed, toFormat and toPrecision, and round (default value). + * UP 0 Away from zero. + * DOWN 1 Towards zero. + * CEIL 2 Towards +Infinity. + * FLOOR 3 Towards -Infinity. + * HALF_UP 4 Towards nearest neighbour. If equidistant, up. + * HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. + * HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. + * HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. + * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. + */ + ROUNDING_MODE = 4, // 0 to 8 + + // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS] + + // The exponent value at and beneath which toString returns exponential notation. + // Number type: -7 + TO_EXP_NEG = -7, // 0 to -MAX + + // The exponent value at and above which toString returns exponential notation. + // Number type: 21 + TO_EXP_POS = 21, // 0 to MAX + + // RANGE : [MIN_EXP, MAX_EXP] + + // The minimum exponent value, beneath which underflow to zero occurs. + // Number type: -324 (5e-324) + MIN_EXP = -1e7, // -1 to -MAX + + // The maximum exponent value, above which overflow to Infinity occurs. + // Number type: 308 (1.7976931348623157e+308) + // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow. + MAX_EXP = 1e7, // 1 to MAX + + // Whether BigNumber Errors are ever thrown. + ERRORS = true, // true or false + + // Change to intValidatorNoErrors if ERRORS is false. + isValidInt = intValidatorWithErrors, // intValidatorWithErrors/intValidatorNoErrors + + // Whether to use cryptographically-secure random number generation, if available. + CRYPTO = false, // true or false + + /* + * The modulo mode used when calculating the modulus: a mod n. + * The quotient (q = a / n) is calculated according to the corresponding rounding mode. + * The remainder (r) is calculated as: r = a - n * q. + * + * UP 0 The remainder is positive if the dividend is negative, else is negative. + * DOWN 1 The remainder has the same sign as the dividend. + * This modulo mode is commonly known as 'truncated division' and is + * equivalent to (a % n) in JavaScript. + * FLOOR 3 The remainder has the same sign as the divisor (Python %). + * HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function. + * EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). + * The remainder is always positive. + * + * The truncated division, floored division, Euclidian division and IEEE 754 remainder + * modes are commonly used for the modulus operation. + * Although the other rounding modes can also be used, they may not give useful results. + */ + MODULO_MODE = 1, // 0 to 9 + + // The maximum number of significant digits of the result of the toPower operation. + // If POW_PRECISION is 0, there will be unlimited significant digits. + POW_PRECISION = 100, // 0 to MAX + + // The format specification used by the BigNumber.prototype.toFormat method. + FORMAT = { + decimalSeparator: '.', + groupSeparator: ',', + groupSize: 3, + secondaryGroupSize: 0, + fractionGroupSeparator: '\xA0', // non-breaking space + fractionGroupSize: 0 + }; + + + /******************************************************************************************/ + + + // CONSTRUCTOR + + + /* + * The BigNumber constructor and exported function. + * Create and return a new instance of a BigNumber object. + * + * n {number|string|BigNumber} A numeric value. + * [b] {number} The base of n. Integer, 2 to 64 inclusive. + */ + function BigNumber( n, b ) { + var c, e, i, num, len, str, + x = this; + + // Enable constructor usage without new. + if ( !( x instanceof BigNumber ) ) { + + // 'BigNumber() constructor call without new: {n}' + if (ERRORS) raise( 26, 'constructor call without new', n ); + return new BigNumber( n, b ); + } + + // 'new BigNumber() base not an integer: {b}' + // 'new BigNumber() base out of range: {b}' + if ( b == null || !isValidInt( b, 2, 64, id, 'base' ) ) { + + // Duplicate. + if ( n instanceof BigNumber ) { + x.s = n.s; + x.e = n.e; + x.c = ( n = n.c ) ? n.slice() : n; + id = 0; + return; + } + + if ( ( num = typeof n == 'number' ) && n * 0 == 0 ) { + x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1; + + // Fast path for integers. + if ( n === ~~n ) { + for ( e = 0, i = n; i >= 10; i /= 10, e++ ); + x.e = e; + x.c = [n]; + id = 0; + return; + } + + str = n + ''; + } else { + if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, num ); + x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; + } + } else { + b = b | 0; + str = n + ''; + + // Ensure return value is rounded to DECIMAL_PLACES as with other bases. + // Allow exponential notation to be used with base 10 argument. + if ( b == 10 ) { + x = new BigNumber( n instanceof BigNumber ? n : str ); + return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE ); + } + + // Avoid potential interpretation of Infinity and NaN as base 44+ values. + // Any number in exponential form will fail due to the [Ee][+-]. + if ( ( num = typeof n == 'number' ) && n * 0 != 0 || + !( new RegExp( '^-?' + ( c = '[' + ALPHABET.slice( 0, b ) + ']+' ) + + '(?:\\.' + c + ')?$',b < 37 ? 'i' : '' ) ).test(str) ) { + return parseNumeric( x, str, num, b ); + } + + if (num) { + x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1; + + if ( ERRORS && str.replace( /^0\.0*|\./, '' ).length > 15 ) { + + // 'new BigNumber() number type has more than 15 significant digits: {n}' + raise( id, tooManyDigits, n ); + } + + // Prevent later check for length on converted number. + num = false; + } else { + x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; + } + + str = convertBase( str, 10, b, x.s ); + } + + // Decimal point? + if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' ); + + // Exponential form? + if ( ( i = str.search( /e/i ) ) > 0 ) { + + // Determine exponent. + if ( e < 0 ) e = i; + e += +str.slice( i + 1 ); + str = str.substring( 0, i ); + } else if ( e < 0 ) { + + // Integer. + e = str.length; + } + + // Determine leading zeros. + for ( i = 0; str.charCodeAt(i) === 48; i++ ); + + // Determine trailing zeros. + for ( len = str.length; str.charCodeAt(--len) === 48; ); + str = str.slice( i, len + 1 ); + + if (str) { + len = str.length; + + // Disallow numbers with over 15 significant digits if number type. + // 'new BigNumber() number type has more than 15 significant digits: {n}' + if ( num && ERRORS && len > 15 ) raise( id, tooManyDigits, x.s * n ); + + e = e - i - 1; + + // Overflow? + if ( e > MAX_EXP ) { + + // Infinity. + x.c = x.e = null; + + // Underflow? + } else if ( e < MIN_EXP ) { + + // Zero. + x.c = [ x.e = 0 ]; + } else { + x.e = e; + x.c = []; + + // Transform base + + // e is the base 10 exponent. + // i is where to slice str to get the first element of the coefficient array. + i = ( e + 1 ) % LOG_BASE; + if ( e < 0 ) i += LOG_BASE; + + if ( i < len ) { + if (i) x.c.push( +str.slice( 0, i ) ); + + for ( len -= LOG_BASE; i < len; ) { + x.c.push( +str.slice( i, i += LOG_BASE ) ); + } + + str = str.slice(i); + i = LOG_BASE - str.length; + } else { + i -= len; + } + + for ( ; i--; str += '0' ); + x.c.push( +str ); + } + } else { + + // Zero. + x.c = [ x.e = 0 ]; + } + + id = 0; + } + + + // CONSTRUCTOR PROPERTIES + + + BigNumber.another = another; + + BigNumber.ROUND_UP = 0; + BigNumber.ROUND_DOWN = 1; + BigNumber.ROUND_CEIL = 2; + BigNumber.ROUND_FLOOR = 3; + BigNumber.ROUND_HALF_UP = 4; + BigNumber.ROUND_HALF_DOWN = 5; + BigNumber.ROUND_HALF_EVEN = 6; + BigNumber.ROUND_HALF_CEIL = 7; + BigNumber.ROUND_HALF_FLOOR = 8; + BigNumber.EUCLID = 9; + + + /* + * Configure infrequently-changing library-wide settings. + * + * Accept an object or an argument list, with one or many of the following properties or + * parameters respectively: + * + * DECIMAL_PLACES {number} Integer, 0 to MAX inclusive + * ROUNDING_MODE {number} Integer, 0 to 8 inclusive + * EXPONENTIAL_AT {number|number[]} Integer, -MAX to MAX inclusive or + * [integer -MAX to 0 incl., 0 to MAX incl.] + * RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or + * [integer -MAX to -1 incl., integer 1 to MAX incl.] + * ERRORS {boolean|number} true, false, 1 or 0 + * CRYPTO {boolean|number} true, false, 1 or 0 + * MODULO_MODE {number} 0 to 9 inclusive + * POW_PRECISION {number} 0 to MAX inclusive + * FORMAT {object} See BigNumber.prototype.toFormat + * decimalSeparator {string} + * groupSeparator {string} + * groupSize {number} + * secondaryGroupSize {number} + * fractionGroupSeparator {string} + * fractionGroupSize {number} + * + * (The values assigned to the above FORMAT object properties are not checked for validity.) + * + * E.g. + * BigNumber.config(20, 4) is equivalent to + * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 }) + * + * Ignore properties/parameters set to null or undefined. + * Return an object with the properties current values. + */ + BigNumber.config = function () { + var v, p, + i = 0, + r = {}, + a = arguments, + o = a[0], + has = o && typeof o == 'object' + ? function () { if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null; } + : function () { if ( a.length > i ) return ( v = a[i++] ) != null; }; + + // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive. + // 'config() DECIMAL_PLACES not an integer: {v}' + // 'config() DECIMAL_PLACES out of range: {v}' + if ( has( p = 'DECIMAL_PLACES' ) && isValidInt( v, 0, MAX, 2, p ) ) { + DECIMAL_PLACES = v | 0; + } + r[p] = DECIMAL_PLACES; + + // ROUNDING_MODE {number} Integer, 0 to 8 inclusive. + // 'config() ROUNDING_MODE not an integer: {v}' + // 'config() ROUNDING_MODE out of range: {v}' + if ( has( p = 'ROUNDING_MODE' ) && isValidInt( v, 0, 8, 2, p ) ) { + ROUNDING_MODE = v | 0; + } + r[p] = ROUNDING_MODE; + + // EXPONENTIAL_AT {number|number[]} + // Integer, -MAX to MAX inclusive or [integer -MAX to 0 inclusive, 0 to MAX inclusive]. + // 'config() EXPONENTIAL_AT not an integer: {v}' + // 'config() EXPONENTIAL_AT out of range: {v}' + if ( has( p = 'EXPONENTIAL_AT' ) ) { + + if ( isArray(v) ) { + if ( isValidInt( v[0], -MAX, 0, 2, p ) && isValidInt( v[1], 0, MAX, 2, p ) ) { + TO_EXP_NEG = v[0] | 0; + TO_EXP_POS = v[1] | 0; + } + } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) { + TO_EXP_NEG = -( TO_EXP_POS = ( v < 0 ? -v : v ) | 0 ); + } + } + r[p] = [ TO_EXP_NEG, TO_EXP_POS ]; + + // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or + // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive]. + // 'config() RANGE not an integer: {v}' + // 'config() RANGE cannot be zero: {v}' + // 'config() RANGE out of range: {v}' + if ( has( p = 'RANGE' ) ) { + + if ( isArray(v) ) { + if ( isValidInt( v[0], -MAX, -1, 2, p ) && isValidInt( v[1], 1, MAX, 2, p ) ) { + MIN_EXP = v[0] | 0; + MAX_EXP = v[1] | 0; + } + } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) { + if ( v | 0 ) MIN_EXP = -( MAX_EXP = ( v < 0 ? -v : v ) | 0 ); + else if (ERRORS) raise( 2, p + ' cannot be zero', v ); + } + } + r[p] = [ MIN_EXP, MAX_EXP ]; + + // ERRORS {boolean|number} true, false, 1 or 0. + // 'config() ERRORS not a boolean or binary digit: {v}' + if ( has( p = 'ERRORS' ) ) { + + if ( v === !!v || v === 1 || v === 0 ) { + id = 0; + isValidInt = ( ERRORS = !!v ) ? intValidatorWithErrors : intValidatorNoErrors; + } else if (ERRORS) { + raise( 2, p + notBool, v ); + } + } + r[p] = ERRORS; + + // CRYPTO {boolean|number} true, false, 1 or 0. + // 'config() CRYPTO not a boolean or binary digit: {v}' + // 'config() crypto unavailable: {crypto}' + if ( has( p = 'CRYPTO' ) ) { + + if ( v === !!v || v === 1 || v === 0 ) { + CRYPTO = !!( v && crypto && typeof crypto == 'object' ); + if ( v && !CRYPTO && ERRORS ) raise( 2, 'crypto unavailable', crypto ); + } else if (ERRORS) { + raise( 2, p + notBool, v ); + } + } + r[p] = CRYPTO; + + // MODULO_MODE {number} Integer, 0 to 9 inclusive. + // 'config() MODULO_MODE not an integer: {v}' + // 'config() MODULO_MODE out of range: {v}' + if ( has( p = 'MODULO_MODE' ) && isValidInt( v, 0, 9, 2, p ) ) { + MODULO_MODE = v | 0; + } + r[p] = MODULO_MODE; + + // POW_PRECISION {number} Integer, 0 to MAX inclusive. + // 'config() POW_PRECISION not an integer: {v}' + // 'config() POW_PRECISION out of range: {v}' + if ( has( p = 'POW_PRECISION' ) && isValidInt( v, 0, MAX, 2, p ) ) { + POW_PRECISION = v | 0; + } + r[p] = POW_PRECISION; + + // FORMAT {object} + // 'config() FORMAT not an object: {v}' + if ( has( p = 'FORMAT' ) ) { + + if ( typeof v == 'object' ) { + FORMAT = v; + } else if (ERRORS) { + raise( 2, p + ' not an object', v ); + } + } + r[p] = FORMAT; + + return r; + }; + + + /* + * Return a new BigNumber whose value is the maximum of the arguments. + * + * arguments {number|string|BigNumber} + */ + BigNumber.max = function () { return maxOrMin( arguments, P.lt ); }; + + + /* + * Return a new BigNumber whose value is the minimum of the arguments. + * + * arguments {number|string|BigNumber} + */ + BigNumber.min = function () { return maxOrMin( arguments, P.gt ); }; + + + /* + * Return a new BigNumber with a random value equal to or greater than 0 and less than 1, + * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing + * zeros are produced). + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * + * 'random() decimal places not an integer: {dp}' + * 'random() decimal places out of range: {dp}' + * 'random() crypto unavailable: {crypto}' + */ + BigNumber.random = (function () { + var pow2_53 = 0x20000000000000; + + // Return a 53 bit integer n, where 0 <= n < 9007199254740992. + // Check if Math.random() produces more than 32 bits of randomness. + // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits. + // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1. + var random53bitInt = (Math.random() * pow2_53) & 0x1fffff + ? function () { return mathfloor( Math.random() * pow2_53 ); } + : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) + + (Math.random() * 0x800000 | 0); }; + + return function (dp) { + var a, b, e, k, v, + i = 0, + c = [], + rand = new BigNumber(ONE); + + dp = dp == null || !isValidInt( dp, 0, MAX, 14 ) ? DECIMAL_PLACES : dp | 0; + k = mathceil( dp / LOG_BASE ); + + if (CRYPTO) { + + // Browsers supporting crypto.getRandomValues. + if ( crypto && crypto.getRandomValues ) { + + a = crypto.getRandomValues( new Uint32Array( k *= 2 ) ); + + for ( ; i < k; ) { + + // 53 bits: + // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2) + // 11111 11111111 11111111 11111111 11100000 00000000 00000000 + // ((Math.pow(2, 32) - 1) >>> 11).toString(2) + // 11111 11111111 11111111 + // 0x20000 is 2^21. + v = a[i] * 0x20000 + (a[i + 1] >>> 11); + + // Rejection sampling: + // 0 <= v < 9007199254740992 + // Probability that v >= 9e15, is + // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251 + if ( v >= 9e15 ) { + b = crypto.getRandomValues( new Uint32Array(2) ); + a[i] = b[0]; + a[i + 1] = b[1]; + } else { + + // 0 <= v <= 8999999999999999 + // 0 <= (v % 1e14) <= 99999999999999 + c.push( v % 1e14 ); + i += 2; + } + } + i = k / 2; + + // Node.js supporting crypto.randomBytes. + } else if ( crypto && crypto.randomBytes ) { + + // buffer + a = crypto.randomBytes( k *= 7 ); + + for ( ; i < k; ) { + + // 0x1000000000000 is 2^48, 0x10000000000 is 2^40 + // 0x100000000 is 2^32, 0x1000000 is 2^24 + // 11111 11111111 11111111 11111111 11111111 11111111 11111111 + // 0 <= v < 9007199254740992 + v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) + + ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) + + ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6]; + + if ( v >= 9e15 ) { + crypto.randomBytes(7).copy( a, i ); + } else { + + // 0 <= (v % 1e14) <= 99999999999999 + c.push( v % 1e14 ); + i += 7; + } + } + i = k / 7; + } else if (ERRORS) { + raise( 14, 'crypto unavailable', crypto ); + } + } + + // Use Math.random: CRYPTO is false or crypto is unavailable and ERRORS is false. + if (!i) { + + for ( ; i < k; ) { + v = random53bitInt(); + if ( v < 9e15 ) c[i++] = v % 1e14; + } + } + + k = c[--i]; + dp %= LOG_BASE; + + // Convert trailing digits to zeros according to dp. + if ( k && dp ) { + v = POWS_TEN[LOG_BASE - dp]; + c[i] = mathfloor( k / v ) * v; + } + + // Remove trailing elements which are zero. + for ( ; c[i] === 0; c.pop(), i-- ); + + // Zero? + if ( i < 0 ) { + c = [ e = 0 ]; + } else { + + // Remove leading elements which are zero and adjust exponent accordingly. + for ( e = -1 ; c[0] === 0; c.shift(), e -= LOG_BASE); + + // Count the digits of the first element of c to determine leading zeros, and... + for ( i = 1, v = c[0]; v >= 10; v /= 10, i++); + + // adjust the exponent accordingly. + if ( i < LOG_BASE ) e -= LOG_BASE - i; + } + + rand.e = e; + rand.c = c; + return rand; + }; + })(); + + + // PRIVATE FUNCTIONS + + + // Convert a numeric string of baseIn to a numeric string of baseOut. + function convertBase( str, baseOut, baseIn, sign ) { + var d, e, k, r, x, xc, y, + i = str.indexOf( '.' ), + dp = DECIMAL_PLACES, + rm = ROUNDING_MODE; + + if ( baseIn < 37 ) str = str.toLowerCase(); + + // Non-integer. + if ( i >= 0 ) { + k = POW_PRECISION; + + // Unlimited precision. + POW_PRECISION = 0; + str = str.replace( '.', '' ); + y = new BigNumber(baseIn); + x = y.pow( str.length - i ); + POW_PRECISION = k; + + // Convert str as if an integer, then restore the fraction part by dividing the + // result by its base raised to a power. + y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e ), 10, baseOut ); + y.e = y.c.length; + } + + // Convert the number as integer. + xc = toBaseOut( str, baseIn, baseOut ); + e = k = xc.length; + + // Remove trailing zeros. + for ( ; xc[--k] == 0; xc.pop() ); + if ( !xc[0] ) return '0'; + + if ( i < 0 ) { + --e; + } else { + x.c = xc; + x.e = e; + + // sign is needed for correct rounding. + x.s = sign; + x = div( x, y, dp, rm, baseOut ); + xc = x.c; + r = x.r; + e = x.e; + } + + d = e + dp + 1; + + // The rounding digit, i.e. the digit to the right of the digit that may be rounded up. + i = xc[d]; + k = baseOut / 2; + r = r || d < 0 || xc[d + 1] != null; + + r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) + : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 || + rm == ( x.s < 0 ? 8 : 7 ) ); + + if ( d < 1 || !xc[0] ) { + + // 1^-dp or 0. + str = r ? toFixedPoint( '1', -dp ) : '0'; + } else { + xc.length = d; + + if (r) { + + // Rounding up may mean the previous digit has to be rounded up and so on. + for ( --baseOut; ++xc[--d] > baseOut; ) { + xc[d] = 0; + + if ( !d ) { + ++e; + xc.unshift(1); + } + } + } + + // Determine trailing zeros. + for ( k = xc.length; !xc[--k]; ); + + // E.g. [4, 11, 15] becomes 4bf. + for ( i = 0, str = ''; i <= k; str += ALPHABET.charAt( xc[i++] ) ); + str = toFixedPoint( str, e ); + } + + // The caller will add the sign. + return str; + } + + + // Perform division in the specified base. Called by div and convertBase. + div = (function () { + + // Assume non-zero x and k. + function multiply( x, k, base ) { + var m, temp, xlo, xhi, + carry = 0, + i = x.length, + klo = k % SQRT_BASE, + khi = k / SQRT_BASE | 0; + + for ( x = x.slice(); i--; ) { + xlo = x[i] % SQRT_BASE; + xhi = x[i] / SQRT_BASE | 0; + m = khi * xlo + xhi * klo; + temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry; + carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi; + x[i] = temp % base; + } + + if (carry) x.unshift(carry); + + return x; + } + + function compare( a, b, aL, bL ) { + var i, cmp; + + if ( aL != bL ) { + cmp = aL > bL ? 1 : -1; + } else { + + for ( i = cmp = 0; i < aL; i++ ) { + + if ( a[i] != b[i] ) { + cmp = a[i] > b[i] ? 1 : -1; + break; + } + } + } + return cmp; + } + + function subtract( a, b, aL, base ) { + var i = 0; + + // Subtract b from a. + for ( ; aL--; ) { + a[aL] -= i; + i = a[aL] < b[aL] ? 1 : 0; + a[aL] = i * base + a[aL] - b[aL]; + } + + // Remove leading zeros. + for ( ; !a[0] && a.length > 1; a.shift() ); + } + + // x: dividend, y: divisor. + return function ( x, y, dp, rm, base ) { + var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0, + yL, yz, + s = x.s == y.s ? 1 : -1, + xc = x.c, + yc = y.c; + + // Either NaN, Infinity or 0? + if ( !xc || !xc[0] || !yc || !yc[0] ) { + + return new BigNumber( + + // Return NaN if either NaN, or both Infinity or 0. + !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN : + + // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0. + xc && xc[0] == 0 || !yc ? s * 0 : s / 0 + ); + } + + q = new BigNumber(s); + qc = q.c = []; + e = x.e - y.e; + s = dp + e + 1; + + if ( !base ) { + base = BASE; + e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE ); + s = s / LOG_BASE | 0; + } + + // Result exponent may be one less then the current value of e. + // The coefficients of the BigNumbers from convertBase may have trailing zeros. + for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ ); + if ( yc[i] > ( xc[i] || 0 ) ) e--; + + if ( s < 0 ) { + qc.push(1); + more = true; + } else { + xL = xc.length; + yL = yc.length; + i = 0; + s += 2; + + // Normalise xc and yc so highest order digit of yc is >= base/2 + + n = mathfloor( base / ( yc[0] + 1 ) ); + + if ( n > 1 ) { + yc = multiply( yc, n, base ); + xc = multiply( xc, n, base ); + yL = yc.length; + xL = xc.length; + } + + xi = yL; + rem = xc.slice( 0, yL ); + remL = rem.length; + + // Add zeros to make remainder as long as divisor. + for ( ; remL < yL; rem[remL++] = 0 ); + yz = yc.slice(); + yz.unshift(0); + yc0 = yc[0]; + if ( yc[1] >= base / 2 ) yc0++; + + do { + n = 0; + + // Compare divisor and remainder. + cmp = compare( yc, rem, yL, remL ); + + // If divisor < remainder. + if ( cmp < 0 ) { + + // Calculate trial digit, n. + + rem0 = rem[0]; + if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 ); + + // n is how many times the divisor goes into the current remainder. + n = mathfloor( rem0 / yc0 ); + + // Algorithm: + // 1. product = divisor * trial digit (n) + // 2. if product > remainder: product -= divisor, n-- + // 3. remainder -= product + // 4. if product was < remainder at 2: + // 5. compare new remainder and divisor + // 6. If remainder > divisor: remainder -= divisor, n++ + + if ( n > 1 ) { + if ( n >= base ) n = base - 1; + + // product = divisor * trial digit. + prod = multiply( yc, n, base ); + prodL = prod.length; + remL = rem.length; + + // Compare product and remainder. + cmp = compare( prod, rem, prodL, remL ); + + // product > remainder. + if ( cmp == 1 ) { + n--; + + // Subtract divisor from product. + subtract( prod, yL < prodL ? yz : yc, prodL, base ); + } + } else { + + // cmp is -1. + // If n is 0, there is no need to compare yc and rem again + // below, so change cmp to 1 to avoid it. + // If n is 1, compare yc and rem again below. + if ( n == 0 ) cmp = n = 1; + prod = yc.slice(); + } + + prodL = prod.length; + if ( prodL < remL ) prod.unshift(0); + + // Subtract product from remainder. + subtract( rem, prod, remL, base ); + + // If product was < previous remainder. + if ( cmp == -1 ) { + remL = rem.length; + + // Compare divisor and new remainder. + cmp = compare( yc, rem, yL, remL ); + + // If divisor < new remainder, subtract divisor from remainder. + if ( cmp < 1 ) { + n++; + + // Subtract divisor from remainder. + subtract( rem, yL < remL ? yz : yc, remL, base ); + } + } + remL = rem.length; + } else if ( cmp === 0 ) { + n++; + rem = [0]; + } + // if cmp === 1, n will be 0 + + // Add the next digit, n, to the result array. + qc[i++] = n; + + // Update the remainder. + if ( cmp && rem[0] ) { + rem[remL++] = xc[xi] || 0; + } else { + rem = [ xc[xi] ]; + remL = 1; + } + } while ( ( xi++ < xL || rem[0] != null ) && s-- ); + + more = rem[0] != null; + + // Leading zero? + if ( !qc[0] ) qc.shift(); + } + + if ( base == BASE ) { + + // To calculate q.e, first get the number of digits of qc[0]. + for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ ); + round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more ); + + // Caller is convertBase. + } else { + q.e = e; + q.r = +more; + } + + return q; + }; + })(); + + + /* + * Return a string representing the value of BigNumber n in fixed-point or exponential + * notation rounded to the specified decimal places or significant digits. + * + * n is a BigNumber. + * i is the index of the last digit required (i.e. the digit that may be rounded up). + * rm is the rounding mode. + * caller is caller id: toExponential 19, toFixed 20, toFormat 21, toPrecision 24. + */ + function format( n, i, rm, caller ) { + var c0, e, ne, len, str; + + rm = rm != null && isValidInt( rm, 0, 8, caller, roundingMode ) + ? rm | 0 : ROUNDING_MODE; + + if ( !n.c ) return n.toString(); + c0 = n.c[0]; + ne = n.e; + + if ( i == null ) { + str = coeffToString( n.c ); + str = caller == 19 || caller == 24 && ne <= TO_EXP_NEG + ? toExponential( str, ne ) + : toFixedPoint( str, ne ); + } else { + n = round( new BigNumber(n), i, rm ); + + // n.e may have changed if the value was rounded up. + e = n.e; + + str = coeffToString( n.c ); + len = str.length; + + // toPrecision returns exponential notation if the number of significant digits + // specified is less than the number of digits necessary to represent the integer + // part of the value in fixed-point notation. + + // Exponential notation. + if ( caller == 19 || caller == 24 && ( i <= e || e <= TO_EXP_NEG ) ) { + + // Append zeros? + for ( ; len < i; str += '0', len++ ); + str = toExponential( str, e ); + + // Fixed-point notation. + } else { + i -= ne; + str = toFixedPoint( str, e ); + + // Append zeros? + if ( e + 1 > len ) { + if ( --i > 0 ) for ( str += '.'; i--; str += '0' ); + } else { + i += e - len; + if ( i > 0 ) { + if ( e + 1 == len ) str += '.'; + for ( ; i--; str += '0' ); + } + } + } + } + + return n.s < 0 && c0 ? '-' + str : str; + } + + + // Handle BigNumber.max and BigNumber.min. + function maxOrMin( args, method ) { + var m, n, + i = 0; + + if ( isArray( args[0] ) ) args = args[0]; + m = new BigNumber( args[0] ); + + for ( ; ++i < args.length; ) { + n = new BigNumber( args[i] ); + + // If any number is NaN, return NaN. + if ( !n.s ) { + m = n; + break; + } else if ( method.call( m, n ) ) { + m = n; + } + } + + return m; + } + + + /* + * Return true if n is an integer in range, otherwise throw. + * Use for argument validation when ERRORS is true. + */ + function intValidatorWithErrors( n, min, max, caller, name ) { + if ( n < min || n > max || n != truncate(n) ) { + raise( caller, ( name || 'decimal places' ) + + ( n < min || n > max ? ' out of range' : ' not an integer' ), n ); + } + + return true; + } + + + /* + * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP. + * Called by minus, plus and times. + */ + function normalise( n, c, e ) { + var i = 1, + j = c.length; + + // Remove trailing zeros. + for ( ; !c[--j]; c.pop() ); + + // Calculate the base 10 exponent. First get the number of digits of c[0]. + for ( j = c[0]; j >= 10; j /= 10, i++ ); + + // Overflow? + if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) { + + // Infinity. + n.c = n.e = null; + + // Underflow? + } else if ( e < MIN_EXP ) { + + // Zero. + n.c = [ n.e = 0 ]; + } else { + n.e = e; + n.c = c; + } + + return n; + } + + + // Handle values that fail the validity test in BigNumber. + parseNumeric = (function () { +// var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, + var basePrefix = /^(-?)0([xbo])/i, + dotAfter = /^([^.]+)\.$/, + dotBefore = /^\.([^.]+)$/, + isInfinityOrNaN = /^-?(Infinity|NaN)$/, +// whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g; + whitespaceOrPlus = /^\s*\+[\w.]|^\s+|\s+$/g; + + return function ( x, str, num, b ) { + var base, + s = num ? str : str.replace( whitespaceOrPlus, '' ); + + // No exception on ±Infinity or NaN. + if ( isInfinityOrNaN.test(s) ) { + x.s = isNaN(s) ? null : s < 0 ? -1 : 1; + } else { + if ( !num ) { + + // basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i + s = s.replace( basePrefix, function ( m, p1, p2 ) { + base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8; + return !b || b == base ? p1 : m; + }); + + if (b) { + base = b; + + // E.g. '1.' to '1', '.1' to '0.1' + s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' ); + } + + if ( str != s ) return new BigNumber( s, base ); + } + + // 'new BigNumber() not a number: {n}' + // 'new BigNumber() not a base {b} number: {n}' + if (ERRORS) raise( id, 'not a' + ( b ? ' base ' + b : '' ) + ' number', str ); + x.s = null; + } + + x.c = x.e = null; + id = 0; + } + })(); + + + // Throw a BigNumber Error. + function raise( caller, msg, val ) { + var error = new Error( [ + 'new BigNumber', // 0 + 'cmp', // 1 + 'config', // 2 + 'div', // 3 + 'divToInt', // 4 + 'eq', // 5 + 'gt', // 6 + 'gte', // 7 + 'lt', // 8 + 'lte', // 9 + 'minus', // 10 + 'mod', // 11 + 'plus', // 12 + 'precision', // 13 + 'random', // 14 + 'round', // 15 + 'shift', // 16 + 'times', // 17 + 'toDigits', // 18 + 'toExponential', // 19 + 'toFixed', // 20 + 'toFormat', // 21 + 'toFraction', // 22 + 'pow', // 23 + 'toPrecision', // 24 + 'toString', // 25 + 'BigNumber' // 26 + ][caller] + '() ' + msg + ': ' + val ); + + error.name = 'BigNumber Error'; + id = 0; + throw error; + } + + + /* + * Round x to sd significant digits using rounding mode rm. Check for over/under-flow. + * If r is truthy, it is known that there are more digits after the rounding digit. + */ + function round( x, sd, rm, r ) { + var d, i, j, k, n, ni, rd, + xc = x.c, + pows10 = POWS_TEN; + + // if x is not Infinity or NaN... + if (xc) { + + // rd is the rounding digit, i.e. the digit after the digit that may be rounded up. + // n is a base 1e14 number, the value of the element of array x.c containing rd. + // ni is the index of n within x.c. + // d is the number of digits of n. + // i is the index of rd within n including leading zeros. + // j is the actual index of rd within n (if < 0, rd is a leading zero). + out: { + + // Get the number of digits of the first element of xc. + for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ ); + i = sd - d; + + // If the rounding digit is in the first element of xc... + if ( i < 0 ) { + i += LOG_BASE; + j = sd; + n = xc[ ni = 0 ]; + + // Get the rounding digit at index j of n. + rd = n / pows10[ d - j - 1 ] % 10 | 0; + } else { + ni = mathceil( ( i + 1 ) / LOG_BASE ); + + if ( ni >= xc.length ) { + + if (r) { + + // Needed by sqrt. + for ( ; xc.length <= ni; xc.push(0) ); + n = rd = 0; + d = 1; + i %= LOG_BASE; + j = i - LOG_BASE + 1; + } else { + break out; + } + } else { + n = k = xc[ni]; + + // Get the number of digits of n. + for ( d = 1; k >= 10; k /= 10, d++ ); + + // Get the index of rd within n. + i %= LOG_BASE; + + // Get the index of rd within n, adjusted for leading zeros. + // The number of leading zeros of n is given by LOG_BASE - d. + j = i - LOG_BASE + d; + + // Get the rounding digit at index j of n. + rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0; + } + } + + r = r || sd < 0 || + + // Are there any non-zero digits after the rounding digit? + // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right + // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714. + xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] ); + + r = rm < 4 + ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) + : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 && + + // Check whether the digit to the left of the rounding digit is odd. + ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 || + rm == ( x.s < 0 ? 8 : 7 ) ); + + if ( sd < 1 || !xc[0] ) { + xc.length = 0; + + if (r) { + + // Convert sd to decimal places. + sd -= x.e + 1; + + // 1, 0.1, 0.01, 0.001, 0.0001 etc. + xc[0] = pows10[ sd % LOG_BASE ]; + x.e = -sd || 0; + } else { + + // Zero. + xc[0] = x.e = 0; + } + + return x; + } + + // Remove excess digits. + if ( i == 0 ) { + xc.length = ni; + k = 1; + ni--; + } else { + xc.length = ni + 1; + k = pows10[ LOG_BASE - i ]; + + // E.g. 56700 becomes 56000 if 7 is the rounding digit. + // j > 0 means i > number of leading zeros of n. + xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0; + } + + // Round up? + if (r) { + + for ( ; ; ) { + + // If the digit to be rounded up is in the first element of xc... + if ( ni == 0 ) { + + // i will be the length of xc[0] before k is added. + for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ ); + j = xc[0] += k; + for ( k = 1; j >= 10; j /= 10, k++ ); + + // if i != k the length has increased. + if ( i != k ) { + x.e++; + if ( xc[0] == BASE ) xc[0] = 1; + } + + break; + } else { + xc[ni] += k; + if ( xc[ni] != BASE ) break; + xc[ni--] = 0; + k = 1; + } + } + } + + // Remove trailing zeros. + for ( i = xc.length; xc[--i] === 0; xc.pop() ); + } + + // Overflow? Infinity. + if ( x.e > MAX_EXP ) { + x.c = x.e = null; + + // Underflow? Zero. + } else if ( x.e < MIN_EXP ) { + x.c = [ x.e = 0 ]; + } + } + + return x; + } + + + // PROTOTYPE/INSTANCE METHODS + + + /* + * Return a new BigNumber whose value is the absolute value of this BigNumber. + */ + P.absoluteValue = P.abs = function () { + var x = new BigNumber(this); + if ( x.s < 0 ) x.s = 1; + return x; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole + * number in the direction of Infinity. + */ + P.ceil = function () { + return round( new BigNumber(this), this.e + 1, 2 ); + }; + + + /* + * Return + * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b), + * -1 if the value of this BigNumber is less than the value of BigNumber(y, b), + * 0 if they have the same value, + * or null if the value of either is NaN. + */ + P.comparedTo = P.cmp = function ( y, b ) { + id = 1; + return compare( this, new BigNumber( y, b ) ); + }; + + + /* + * Return the number of decimal places of the value of this BigNumber, or null if the value + * of this BigNumber is ±Infinity or NaN. + */ + P.decimalPlaces = P.dp = function () { + var n, v, + c = this.c; + + if ( !c ) return null; + n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE; + + // Subtract the number of trailing zeros of the last number. + if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- ); + if ( n < 0 ) n = 0; + + return n; + }; + + + /* + * n / 0 = I + * n / N = N + * n / I = 0 + * 0 / n = 0 + * 0 / 0 = N + * 0 / N = N + * 0 / I = 0 + * N / n = N + * N / 0 = N + * N / N = N + * N / I = N + * I / n = I + * I / 0 = I + * I / N = N + * I / I = N + * + * Return a new BigNumber whose value is the value of this BigNumber divided by the value of + * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE. + */ + P.dividedBy = P.div = function ( y, b ) { + id = 3; + return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE ); + }; + + + /* + * Return a new BigNumber whose value is the integer part of dividing the value of this + * BigNumber by the value of BigNumber(y, b). + */ + P.dividedToIntegerBy = P.divToInt = function ( y, b ) { + id = 4; + return div( this, new BigNumber( y, b ), 0, 1 ); + }; + + + /* + * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b), + * otherwise returns false. + */ + P.equals = P.eq = function ( y, b ) { + id = 5; + return compare( this, new BigNumber( y, b ) ) === 0; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole + * number in the direction of -Infinity. + */ + P.floor = function () { + return round( new BigNumber(this), this.e + 1, 3 ); + }; + + + /* + * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b), + * otherwise returns false. + */ + P.greaterThan = P.gt = function ( y, b ) { + id = 6; + return compare( this, new BigNumber( y, b ) ) > 0; + }; + + + /* + * Return true if the value of this BigNumber is greater than or equal to the value of + * BigNumber(y, b), otherwise returns false. + */ + P.greaterThanOrEqualTo = P.gte = function ( y, b ) { + id = 7; + return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0; + + }; + + + /* + * Return true if the value of this BigNumber is a finite number, otherwise returns false. + */ + P.isFinite = function () { + return !!this.c; + }; + + + /* + * Return true if the value of this BigNumber is an integer, otherwise return false. + */ + P.isInteger = P.isInt = function () { + return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2; + }; + + + /* + * Return true if the value of this BigNumber is NaN, otherwise returns false. + */ + P.isNaN = function () { + return !this.s; + }; + + + /* + * Return true if the value of this BigNumber is negative, otherwise returns false. + */ + P.isNegative = P.isNeg = function () { + return this.s < 0; + }; + + + /* + * Return true if the value of this BigNumber is 0 or -0, otherwise returns false. + */ + P.isZero = function () { + return !!this.c && this.c[0] == 0; + }; + + + /* + * Return true if the value of this BigNumber is less than the value of BigNumber(y, b), + * otherwise returns false. + */ + P.lessThan = P.lt = function ( y, b ) { + id = 8; + return compare( this, new BigNumber( y, b ) ) < 0; + }; + + + /* + * Return true if the value of this BigNumber is less than or equal to the value of + * BigNumber(y, b), otherwise returns false. + */ + P.lessThanOrEqualTo = P.lte = function ( y, b ) { + id = 9; + return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0; + }; + + + /* + * n - 0 = n + * n - N = N + * n - I = -I + * 0 - n = -n + * 0 - 0 = 0 + * 0 - N = N + * 0 - I = -I + * N - n = N + * N - 0 = N + * N - N = N + * N - I = N + * I - n = I + * I - 0 = I + * I - N = N + * I - I = N + * + * Return a new BigNumber whose value is the value of this BigNumber minus the value of + * BigNumber(y, b). + */ + P.minus = P.sub = function ( y, b ) { + var i, j, t, xLTy, + x = this, + a = x.s; + + id = 10; + y = new BigNumber( y, b ); + b = y.s; + + // Either NaN? + if ( !a || !b ) return new BigNumber(NaN); + + // Signs differ? + if ( a != b ) { + y.s = -b; + return x.plus(y); + } + + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + + if ( !xe || !ye ) { + + // Either Infinity? + if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN ); + + // Either zero? + if ( !xc[0] || !yc[0] ) { + + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. + return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x : + + // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity + ROUNDING_MODE == 3 ? -0 : 0 ); + } + } + + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + + // Determine which is the bigger number. + if ( a = xe - ye ) { + + if ( xLTy = a < 0 ) { + a = -a; + t = xc; + } else { + ye = xe; + t = yc; + } + + t.reverse(); + + // Prepend zeros to equalise exponents. + for ( b = a; b--; t.push(0) ); + t.reverse(); + } else { + + // Exponents equal. Check digit by digit. + j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b; + + for ( a = b = 0; b < j; b++ ) { + + if ( xc[b] != yc[b] ) { + xLTy = xc[b] < yc[b]; + break; + } + } + } + + // x < y? Point xc to the array of the bigger number. + if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s; + + b = ( j = yc.length ) - ( i = xc.length ); + + // Append zeros to xc if shorter. + // No need to add zeros to yc if shorter as subtract only needs to start at yc.length. + if ( b > 0 ) for ( ; b--; xc[i++] = 0 ); + b = BASE - 1; + + // Subtract yc from xc. + for ( ; j > a; ) { + + if ( xc[--j] < yc[j] ) { + for ( i = j; i && !xc[--i]; xc[i] = b ); + --xc[i]; + xc[j] += BASE; + } + + xc[j] -= yc[j]; + } + + // Remove leading zeros and adjust exponent accordingly. + for ( ; xc[0] == 0; xc.shift(), --ye ); + + // Zero? + if ( !xc[0] ) { + + // Following IEEE 754 (2008) 6.3, + // n - n = +0 but n - n = -0 when rounding towards -Infinity. + y.s = ROUNDING_MODE == 3 ? -1 : 1; + y.c = [ y.e = 0 ]; + return y; + } + + // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity + // for finite x and y. + return normalise( y, xc, ye ); + }; + + + /* + * n % 0 = N + * n % N = N + * n % I = n + * 0 % n = 0 + * -0 % n = -0 + * 0 % 0 = N + * 0 % N = N + * 0 % I = 0 + * N % n = N + * N % 0 = N + * N % N = N + * N % I = N + * I % n = N + * I % 0 = N + * I % N = N + * I % I = N + * + * Return a new BigNumber whose value is the value of this BigNumber modulo the value of + * BigNumber(y, b). The result depends on the value of MODULO_MODE. + */ + P.modulo = P.mod = function ( y, b ) { + var q, s, + x = this; + + id = 11; + y = new BigNumber( y, b ); + + // Return NaN if x is Infinity or NaN, or y is NaN or zero. + if ( !x.c || !y.s || y.c && !y.c[0] ) { + return new BigNumber(NaN); + + // Return x if y is Infinity or x is zero. + } else if ( !y.c || x.c && !x.c[0] ) { + return new BigNumber(x); + } + + if ( MODULO_MODE == 9 ) { + + // Euclidian division: q = sign(y) * floor(x / abs(y)) + // r = x - qy where 0 <= r < abs(y) + s = y.s; + y.s = 1; + q = div( x, y, 0, 3 ); + y.s = s; + q.s *= s; + } else { + q = div( x, y, 0, MODULO_MODE ); + } + + return x.minus( q.times(y) ); + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber negated, + * i.e. multiplied by -1. + */ + P.negated = P.neg = function () { + var x = new BigNumber(this); + x.s = -x.s || null; + return x; + }; + + + /* + * n + 0 = n + * n + N = N + * n + I = I + * 0 + n = n + * 0 + 0 = 0 + * 0 + N = N + * 0 + I = I + * N + n = N + * N + 0 = N + * N + N = N + * N + I = N + * I + n = I + * I + 0 = I + * I + N = N + * I + I = I + * + * Return a new BigNumber whose value is the value of this BigNumber plus the value of + * BigNumber(y, b). + */ + P.plus = P.add = function ( y, b ) { + var t, + x = this, + a = x.s; + + id = 12; + y = new BigNumber( y, b ); + b = y.s; + + // Either NaN? + if ( !a || !b ) return new BigNumber(NaN); + + // Signs differ? + if ( a != b ) { + y.s = -b; + return x.minus(y); + } + + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + + if ( !xe || !ye ) { + + // Return ±Infinity if either ±Infinity. + if ( !xc || !yc ) return new BigNumber( a / 0 ); + + // Either zero? + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. + if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 ); + } + + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + + // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts. + if ( a = xe - ye ) { + if ( a > 0 ) { + ye = xe; + t = yc; + } else { + a = -a; + t = xc; + } + + t.reverse(); + for ( ; a--; t.push(0) ); + t.reverse(); + } + + a = xc.length; + b = yc.length; + + // Point xc to the longer array, and b to the shorter length. + if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a; + + // Only start adding at yc.length - 1 as the further digits of xc can be ignored. + for ( a = 0; b; ) { + a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0; + xc[b] %= BASE; + } + + if (a) { + xc.unshift(a); + ++ye; + } + + // No need to check for zero, as +x + +y != 0 && -x + -y != 0 + // ye = MAX_EXP + 1 possible + return normalise( y, xc, ye ); + }; + + + /* + * Return the number of significant digits of the value of this BigNumber. + * + * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0. + */ + P.precision = P.sd = function (z) { + var n, v, + x = this, + c = x.c; + + // 'precision() argument not a boolean or binary digit: {z}' + if ( z != null && z !== !!z && z !== 1 && z !== 0 ) { + if (ERRORS) raise( 13, 'argument' + notBool, z ); + if ( z != !!z ) z = null; + } + + if ( !c ) return null; + v = c.length - 1; + n = v * LOG_BASE + 1; + + if ( v = c[v] ) { + + // Subtract the number of trailing zeros of the last element. + for ( ; v % 10 == 0; v /= 10, n-- ); + + // Add the number of digits of the first element. + for ( v = c[0]; v >= 10; v /= 10, n++ ); + } + + if ( z && x.e + 1 > n ) n = x.e + 1; + + return n; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of + * dp decimal places using rounding mode rm, or to 0 and ROUNDING_MODE respectively if + * omitted. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'round() decimal places out of range: {dp}' + * 'round() decimal places not an integer: {dp}' + * 'round() rounding mode not an integer: {rm}' + * 'round() rounding mode out of range: {rm}' + */ + P.round = function ( dp, rm ) { + var n = new BigNumber(this); + + if ( dp == null || isValidInt( dp, 0, MAX, 15 ) ) { + round( n, ~~dp + this.e + 1, rm == null || + !isValidInt( rm, 0, 8, 15, roundingMode ) ? ROUNDING_MODE : rm | 0 ); + } + + return n; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber shifted by k places + * (powers of 10). Shift to the right if n > 0, and to the left if n < 0. + * + * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. + * + * If k is out of range and ERRORS is false, the result will be ±0 if k < 0, or ±Infinity + * otherwise. + * + * 'shift() argument not an integer: {k}' + * 'shift() argument out of range: {k}' + */ + P.shift = function (k) { + var n = this; + return isValidInt( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 16, 'argument' ) + + // k < 1e+21, or truncate(k) will produce exponential notation. + ? n.times( '1e' + truncate(k) ) + : new BigNumber( n.c && n.c[0] && ( k < -MAX_SAFE_INTEGER || k > MAX_SAFE_INTEGER ) + ? n.s * ( k < 0 ? 0 : 1 / 0 ) + : n ); + }; + + + /* + * sqrt(-n) = N + * sqrt( N) = N + * sqrt(-I) = N + * sqrt( I) = I + * sqrt( 0) = 0 + * sqrt(-0) = -0 + * + * Return a new BigNumber whose value is the square root of the value of this BigNumber, + * rounded according to DECIMAL_PLACES and ROUNDING_MODE. + */ + P.squareRoot = P.sqrt = function () { + var m, n, r, rep, t, + x = this, + c = x.c, + s = x.s, + e = x.e, + dp = DECIMAL_PLACES + 4, + half = new BigNumber('0.5'); + + // Negative/NaN/Infinity/zero? + if ( s !== 1 || !c || !c[0] ) { + return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 ); + } + + // Initial estimate. + s = Math.sqrt( +x ); + + // Math.sqrt underflow/overflow? + // Pass x to Math.sqrt as integer, then adjust the exponent of the result. + if ( s == 0 || s == 1 / 0 ) { + n = coeffToString(c); + if ( ( n.length + e ) % 2 == 0 ) n += '0'; + s = Math.sqrt(n); + e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 ); + + if ( s == 1 / 0 ) { + n = '1e' + e; + } else { + n = s.toExponential(); + n = n.slice( 0, n.indexOf('e') + 1 ) + e; + } + + r = new BigNumber(n); + } else { + r = new BigNumber( s + '' ); + } + + // Check for zero. + // r could be zero if MIN_EXP is changed after the this value was created. + // This would cause a division by zero (x/t) and hence Infinity below, which would cause + // coeffToString to throw. + if ( r.c[0] ) { + e = r.e; + s = e + dp; + if ( s < 3 ) s = 0; + + // Newton-Raphson iteration. + for ( ; ; ) { + t = r; + r = half.times( t.plus( div( x, t, dp, 1 ) ) ); + + if ( coeffToString( t.c ).slice( 0, s ) === ( n = + coeffToString( r.c ) ).slice( 0, s ) ) { + + // The exponent of r may here be one less than the final result exponent, + // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits + // are indexed correctly. + if ( r.e < e ) --s; + n = n.slice( s - 3, s + 1 ); + + // The 4th rounding digit may be in error by -1 so if the 4 rounding digits + // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the + // iteration. + if ( n == '9999' || !rep && n == '4999' ) { + + // On the first iteration only, check to see if rounding up gives the + // exact result as the nines may infinitely repeat. + if ( !rep ) { + round( t, t.e + DECIMAL_PLACES + 2, 0 ); + + if ( t.times(t).eq(x) ) { + r = t; + break; + } + } + + dp += 4; + s += 4; + rep = 1; + } else { + + // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact + // result. If not, then there are further digits and m will be truthy. + if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) { + + // Truncate to the first rounding digit. + round( r, r.e + DECIMAL_PLACES + 2, 1 ); + m = !r.times(r).eq(x); + } + + break; + } + } + } + } + + return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m ); + }; + + + /* + * n * 0 = 0 + * n * N = N + * n * I = I + * 0 * n = 0 + * 0 * 0 = 0 + * 0 * N = N + * 0 * I = N + * N * n = N + * N * 0 = N + * N * N = N + * N * I = N + * I * n = I + * I * 0 = N + * I * N = N + * I * I = I + * + * Return a new BigNumber whose value is the value of this BigNumber times the value of + * BigNumber(y, b). + */ + P.times = P.mul = function ( y, b ) { + var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc, + base, sqrtBase, + x = this, + xc = x.c, + yc = ( id = 17, y = new BigNumber( y, b ) ).c; + + // Either NaN, ±Infinity or ±0? + if ( !xc || !yc || !xc[0] || !yc[0] ) { + + // Return NaN if either is NaN, or one is 0 and the other is Infinity. + if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) { + y.c = y.e = y.s = null; + } else { + y.s *= x.s; + + // Return ±Infinity if either is ±Infinity. + if ( !xc || !yc ) { + y.c = y.e = null; + + // Return ±0 if either is ±0. + } else { + y.c = [0]; + y.e = 0; + } + } + + return y; + } + + e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE ); + y.s *= x.s; + xcL = xc.length; + ycL = yc.length; + + // Ensure xc points to longer array and xcL to its length. + if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i; + + // Initialise the result array with zeros. + for ( i = xcL + ycL, zc = []; i--; zc.push(0) ); + + base = BASE; + sqrtBase = SQRT_BASE; + + for ( i = ycL; --i >= 0; ) { + c = 0; + ylo = yc[i] % sqrtBase; + yhi = yc[i] / sqrtBase | 0; + + for ( k = xcL, j = i + k; j > i; ) { + xlo = xc[--k] % sqrtBase; + xhi = xc[k] / sqrtBase | 0; + m = yhi * xlo + xhi * ylo; + xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c; + c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi; + zc[j--] = xlo % base; + } + + zc[j] = c; + } + + if (c) { + ++e; + } else { + zc.shift(); + } + + return normalise( y, zc, e ); + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of + * sd significant digits using rounding mode rm, or ROUNDING_MODE if rm is omitted. + * + * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toDigits() precision out of range: {sd}' + * 'toDigits() precision not an integer: {sd}' + * 'toDigits() rounding mode not an integer: {rm}' + * 'toDigits() rounding mode out of range: {rm}' + */ + P.toDigits = function ( sd, rm ) { + var n = new BigNumber(this); + sd = sd == null || !isValidInt( sd, 1, MAX, 18, 'precision' ) ? null : sd | 0; + rm = rm == null || !isValidInt( rm, 0, 8, 18, roundingMode ) ? ROUNDING_MODE : rm | 0; + return sd ? round( n, sd, rm ) : n; + }; + + + /* + * Return a string representing the value of this BigNumber in exponential notation and + * rounded using ROUNDING_MODE to dp fixed decimal places. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toExponential() decimal places not an integer: {dp}' + * 'toExponential() decimal places out of range: {dp}' + * 'toExponential() rounding mode not an integer: {rm}' + * 'toExponential() rounding mode out of range: {rm}' + */ + P.toExponential = function ( dp, rm ) { + return format( this, + dp != null && isValidInt( dp, 0, MAX, 19 ) ? ~~dp + 1 : null, rm, 19 ); + }; + + + /* + * Return a string representing the value of this BigNumber in fixed-point notation rounding + * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted. + * + * Note: as with JavaScript's number type, (-0).toFixed(0) is '0', + * but e.g. (-0.00001).toFixed(0) is '-0'. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toFixed() decimal places not an integer: {dp}' + * 'toFixed() decimal places out of range: {dp}' + * 'toFixed() rounding mode not an integer: {rm}' + * 'toFixed() rounding mode out of range: {rm}' + */ + P.toFixed = function ( dp, rm ) { + return format( this, dp != null && isValidInt( dp, 0, MAX, 20 ) + ? ~~dp + this.e + 1 : null, rm, 20 ); + }; + + + /* + * Return a string representing the value of this BigNumber in fixed-point notation rounded + * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties + * of the FORMAT object (see BigNumber.config). + * + * FORMAT = { + * decimalSeparator : '.', + * groupSeparator : ',', + * groupSize : 3, + * secondaryGroupSize : 0, + * fractionGroupSeparator : '\xA0', // non-breaking space + * fractionGroupSize : 0 + * }; + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toFormat() decimal places not an integer: {dp}' + * 'toFormat() decimal places out of range: {dp}' + * 'toFormat() rounding mode not an integer: {rm}' + * 'toFormat() rounding mode out of range: {rm}' + */ + P.toFormat = function ( dp, rm ) { + var str = format( this, dp != null && isValidInt( dp, 0, MAX, 21 ) + ? ~~dp + this.e + 1 : null, rm, 21 ); + + if ( this.c ) { + var i, + arr = str.split('.'), + g1 = +FORMAT.groupSize, + g2 = +FORMAT.secondaryGroupSize, + groupSeparator = FORMAT.groupSeparator, + intPart = arr[0], + fractionPart = arr[1], + isNeg = this.s < 0, + intDigits = isNeg ? intPart.slice(1) : intPart, + len = intDigits.length; + + if (g2) i = g1, g1 = g2, g2 = i, len -= i; + + if ( g1 > 0 && len > 0 ) { + i = len % g1 || g1; + intPart = intDigits.substr( 0, i ); + + for ( ; i < len; i += g1 ) { + intPart += groupSeparator + intDigits.substr( i, g1 ); + } + + if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i); + if (isNeg) intPart = '-' + intPart; + } + + str = fractionPart + ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize ) + ? fractionPart.replace( new RegExp( '\\d{' + g2 + '}\\B', 'g' ), + '$&' + FORMAT.fractionGroupSeparator ) + : fractionPart ) + : intPart; + } + + return str; + }; + + + /* + * Return a string array representing the value of this BigNumber as a simple fraction with + * an integer numerator and an integer denominator. The denominator will be a positive + * non-zero value less than or equal to the specified maximum denominator. If a maximum + * denominator is not specified, the denominator will be the lowest value necessary to + * represent the number exactly. + * + * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator. + * + * 'toFraction() max denominator not an integer: {md}' + * 'toFraction() max denominator out of range: {md}' + */ + P.toFraction = function (md) { + var arr, d0, d2, e, exp, n, n0, q, s, + k = ERRORS, + x = this, + xc = x.c, + d = new BigNumber(ONE), + n1 = d0 = new BigNumber(ONE), + d1 = n0 = new BigNumber(ONE); + + if ( md != null ) { + ERRORS = false; + n = new BigNumber(md); + ERRORS = k; + + if ( !( k = n.isInt() ) || n.lt(ONE) ) { + + if (ERRORS) { + raise( 22, + 'max denominator ' + ( k ? 'out of range' : 'not an integer' ), md ); + } + + // ERRORS is false: + // If md is a finite non-integer >= 1, round it to an integer and use it. + md = !k && n.c && round( n, n.e + 1, 1 ).gte(ONE) ? n : null; + } + } + + if ( !xc ) return x.toString(); + s = coeffToString(xc); + + // Determine initial denominator. + // d is a power of 10 and the minimum max denominator that specifies the value exactly. + e = d.e = s.length - x.e - 1; + d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ]; + md = !md || n.cmp(d) > 0 ? ( e > 0 ? d : n1 ) : n; + + exp = MAX_EXP; + MAX_EXP = 1 / 0; + n = new BigNumber(s); + + // n0 = d1 = 0 + n0.c[0] = 0; + + for ( ; ; ) { + q = div( n, d, 0, 1 ); + d2 = d0.plus( q.times(d1) ); + if ( d2.cmp(md) == 1 ) break; + d0 = d1; + d1 = d2; + n1 = n0.plus( q.times( d2 = n1 ) ); + n0 = d2; + d = n.minus( q.times( d2 = d ) ); + n = d2; + } + + d2 = div( md.minus(d0), d1, 0, 1 ); + n0 = n0.plus( d2.times(n1) ); + d0 = d0.plus( d2.times(d1) ); + n0.s = n1.s = x.s; + e *= 2; + + // Determine which fraction is closer to x, n0/d0 or n1/d1 + arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().cmp( + div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1 + ? [ n1.toString(), d1.toString() ] + : [ n0.toString(), d0.toString() ]; + + MAX_EXP = exp; + return arr; + }; + + + /* + * Return the value of this BigNumber converted to a number primitive. + */ + P.toNumber = function () { + var x = this; + + // Ensure zero has correct sign. + return +x || ( x.s ? x.s * 0 : NaN ); + }; + + + /* + * Return a BigNumber whose value is the value of this BigNumber raised to the power n. + * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE. + * If POW_PRECISION is not 0, round to POW_PRECISION using ROUNDING_MODE. + * + * n {number} Integer, -9007199254740992 to 9007199254740992 inclusive. + * (Performs 54 loop iterations for n of 9007199254740992.) + * + * 'pow() exponent not an integer: {n}' + * 'pow() exponent out of range: {n}' + */ + P.toPower = P.pow = function (n) { + var k, y, + i = mathfloor( n < 0 ? -n : +n ), + x = this; + + // Pass ±Infinity to Math.pow if exponent is out of range. + if ( !isValidInt( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 23, 'exponent' ) && + ( !isFinite(n) || i > MAX_SAFE_INTEGER && ( n /= 0 ) || + parseFloat(n) != n && !( n = NaN ) ) ) { + return new BigNumber( Math.pow( +x, n ) ); + } + + // Truncating each coefficient array to a length of k after each multiplication equates + // to truncating significant digits to POW_PRECISION + [28, 41], i.e. there will be a + // minimum of 28 guard digits retained. (Using + 1.5 would give [9, 21] guard digits.) + k = POW_PRECISION ? mathceil( POW_PRECISION / LOG_BASE + 2 ) : 0; + y = new BigNumber(ONE); + + for ( ; ; ) { + + if ( i % 2 ) { + y = y.times(x); + if ( !y.c ) break; + if ( k && y.c.length > k ) y.c.length = k; + } + + i = mathfloor( i / 2 ); + if ( !i ) break; + + x = x.times(x); + if ( k && x.c && x.c.length > k ) x.c.length = k; + } + + if ( n < 0 ) y = ONE.div(y); + return k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y; + }; + + + /* + * Return a string representing the value of this BigNumber rounded to sd significant digits + * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits + * necessary to represent the integer part of the value in fixed-point notation, then use + * exponential notation. + * + * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toPrecision() precision not an integer: {sd}' + * 'toPrecision() precision out of range: {sd}' + * 'toPrecision() rounding mode not an integer: {rm}' + * 'toPrecision() rounding mode out of range: {rm}' + */ + P.toPrecision = function ( sd, rm ) { + return format( this, sd != null && isValidInt( sd, 1, MAX, 24, 'precision' ) + ? sd | 0 : null, rm, 24 ); + }; + + + /* + * Return a string representing the value of this BigNumber in base b, or base 10 if b is + * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and + * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent + * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than + * TO_EXP_NEG, return exponential notation. + * + * [b] {number} Integer, 2 to 64 inclusive. + * + * 'toString() base not an integer: {b}' + * 'toString() base out of range: {b}' + */ + P.toString = function (b) { + var str, + n = this, + s = n.s, + e = n.e; + + // Infinity or NaN? + if ( e === null ) { + + if (s) { + str = 'Infinity'; + if ( s < 0 ) str = '-' + str; + } else { + str = 'NaN'; + } + } else { + str = coeffToString( n.c ); + + if ( b == null || !isValidInt( b, 2, 64, 25, 'base' ) ) { + str = e <= TO_EXP_NEG || e >= TO_EXP_POS + ? toExponential( str, e ) + : toFixedPoint( str, e ); + } else { + str = convertBase( toFixedPoint( str, e ), b | 0, 10, s ); + } + + if ( s < 0 && n.c[0] ) str = '-' + str; + } + + return str; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber truncated to a whole + * number. + */ + P.truncated = P.trunc = function () { + return round( new BigNumber(this), this.e + 1, 1 ); + }; + + + + /* + * Return as toString, but do not accept a base argument. + */ + P.valueOf = P.toJSON = function () { + return this.toString(); + }; + + + // Aliases for BigDecimal methods. + //P.add = P.plus; // P.add included above + //P.subtract = P.minus; // P.sub included above + //P.multiply = P.times; // P.mul included above + //P.divide = P.div; + //P.remainder = P.mod; + //P.compareTo = P.cmp; + //P.negate = P.neg; + + + if ( configObj != null ) BigNumber.config(configObj); + + return BigNumber; + } + + + // PRIVATE HELPER FUNCTIONS + + + function bitFloor(n) { + var i = n | 0; + return n > 0 || n === i ? i : i - 1; + } + + + // Return a coefficient array as a string of base 10 digits. + function coeffToString(a) { + var s, z, + i = 1, + j = a.length, + r = a[0] + ''; + + for ( ; i < j; ) { + s = a[i++] + ''; + z = LOG_BASE - s.length; + for ( ; z--; s = '0' + s ); + r += s; + } + + // Determine trailing zeros. + for ( j = r.length; r.charCodeAt(--j) === 48; ); + return r.slice( 0, j + 1 || 1 ); + } + + + // Compare the value of BigNumbers x and y. + function compare( x, y ) { + var a, b, + xc = x.c, + yc = y.c, + i = x.s, + j = y.s, + k = x.e, + l = y.e; + + // Either NaN? + if ( !i || !j ) return null; + + a = xc && !xc[0]; + b = yc && !yc[0]; + + // Either zero? + if ( a || b ) return a ? b ? 0 : -j : i; + + // Signs differ? + if ( i != j ) return i; + + a = i < 0; + b = k == l; + + // Either Infinity? + if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1; + + // Compare exponents. + if ( !b ) return k > l ^ a ? 1 : -1; + + j = ( k = xc.length ) < ( l = yc.length ) ? k : l; + + // Compare digit by digit. + for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1; + + // Compare lengths. + return k == l ? 0 : k > l ^ a ? 1 : -1; + } + + + /* + * Return true if n is a valid number in range, otherwise false. + * Use for argument validation when ERRORS is false. + * Note: parseInt('1e+1') == 1 but parseFloat('1e+1') == 10. + */ + function intValidatorNoErrors( n, min, max ) { + return ( n = truncate(n) ) >= min && n <= max; + } + + + function isArray(obj) { + return Object.prototype.toString.call(obj) == '[object Array]'; + } + + + /* + * Convert string of baseIn to an array of numbers of baseOut. + * Eg. convertBase('255', 10, 16) returns [15, 15]. + * Eg. convertBase('ff', 16, 10) returns [2, 5, 5]. + */ + function toBaseOut( str, baseIn, baseOut ) { + var j, + arr = [0], + arrL, + i = 0, + len = str.length; + + for ( ; i < len; ) { + for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn ); + arr[ j = 0 ] += ALPHABET.indexOf( str.charAt( i++ ) ); + + for ( ; j < arr.length; j++ ) { + + if ( arr[j] > baseOut - 1 ) { + if ( arr[j + 1] == null ) arr[j + 1] = 0; + arr[j + 1] += arr[j] / baseOut | 0; + arr[j] %= baseOut; + } + } + } + + return arr.reverse(); + } + + + function toExponential( str, e ) { + return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) + + ( e < 0 ? 'e' : 'e+' ) + e; + } + + + function toFixedPoint( str, e ) { + var len, z; + + // Negative exponent? + if ( e < 0 ) { + + // Prepend zeros. + for ( z = '0.'; ++e; z += '0' ); + str = z + str; + + // Positive exponent + } else { + len = str.length; + + // Append zeros. + if ( ++e > len ) { + for ( z = '0', e -= len; --e; z += '0' ); + str += z; + } else if ( e < len ) { + str = str.slice( 0, e ) + '.' + str.slice(e); + } + } + + return str; + } + + + function truncate(n) { + n = parseFloat(n); + return n < 0 ? mathceil(n) : mathfloor(n); + } + + + // EXPORT + + + BigNumber = another(); + + // AMD. + if ( typeof define == 'function' && define.amd ) { + define( function () { return BigNumber; } ); + + // Node and other environments that support module.exports. + } else if ( typeof module != 'undefined' && module.exports ) { + module.exports = BigNumber; + if ( !crypto ) try { crypto = require('crypto'); } catch (e) {} + + // Browser. + } else { + global.BigNumber = BigNumber; + } +})(this); + +},{"crypto":1}],"natspec":[function(require,module,exports){ +/* + This file is part of natspec.js. + + natspec.js 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. + + natspec.js 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 natspec.js. If not, see . +*/ +/** @file natspec.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var abi = require('./node_modules/ethereum.js/lib/abi.js'); + +/** + * This object should be used to evaluate natspec expression + * It has one method evaluateExpression which shoul be used + */ +var natspec = (function () { + /// Helper method + /// Should be called to copy values from object to global context + var copyToContext = function (obj, context) { + Object.keys(obj).forEach(function (key) { + context[key] = obj[key]; + }); + } + + /// generate codes, which will be evaluated + var generateCode = function (obj) { + return Object.keys(obj).reduce(function (acc, key) { + return acc + "var " + key + " = context['" + key + "'];\n"; + }, ""); + }; + + /// Helper method + /// Should be called to get method with given name from the abi + /// @param contract's abi + /// @param name of the method that we are looking for + var getMethodWithName = function(abi, name) { + return abi.filter(function (method) { + return method.name === name; + })[0]; + }; + + /// Function called to get all contract method input variables + /// @returns hashmap with all contract's method input variables + var getMethodInputParams = function (method, transaction) { + // do it with output formatter (cause we have to decode) + var params = abi.formatOutput(method.inputs, '0x' + transaction.params[0].data.slice(10)); + + return method.inputs.reduce(function (acc, current, index) { + acc[current.name] = params[index]; + return acc; + }, {}); + }; + + /// Should be called to evaluate expression + var mapExpressionsToEvaluate = function (expression, cb) { + var evaluatedExpression = ""; + + // match everything in backtick + var pattern = /\` + "`" + `(?:\\.|[^` + "`" + `\\])*\` + "`" + `/gim + var match; + var lastIndex = 0; + while ((match = pattern.exec(expression)) !== null) { + var startIndex = pattern.lastIndex - match[0].length; + var toEval = match[0].slice(1, match[0].length - 1); + evaluatedExpression += expression.slice(lastIndex, startIndex); + var evaluatedPart = cb(toEval); + evaluatedExpression += evaluatedPart; + lastIndex = pattern.lastIndex; + } + + evaluatedExpression += expression.slice(lastIndex); + + return evaluatedExpression; + }; + + /// Should be called to evaluate single expression + /// Is internally using javascript's 'eval' method + /// @param expression which should be evaluated + /// @param [call] object containing contract abi, transaction, called method + /// TODO: separate evaluation from getting input params, so as not to spoil 'evaluateExpression' function + var evaluateExpression = function (expression, call) { + //var self = this; + var context = {}; + + if (!!call) { + try { + var method = getMethodWithName(call.abi, call.method); + var params = getMethodInputParams(method, call.transaction); + copyToContext(params, context); + } + catch (err) { + return "Natspec evaluation failed, wrong input params"; + } + } + + var code = generateCode(context); + + var evaluatedExpression = mapExpressionsToEvaluate(expression, function (toEval) { + try { + var fn = new Function("context", code + "return " + toEval + ";"); + return fn(context).toString(); + } + catch (err) { + return 'undefined'; + } + }); + + return evaluatedExpression; + }; + + return { + evaluateExpression: evaluateExpression + }; + +})(); + +module.exports = natspec; + + +},{"./node_modules/ethereum.js/lib/abi.js":3}]},{},[]); +` diff --git a/ethutil/natspec/natspec_test.go b/ethutil/natspec/natspec_test.go index 48a9cb25c..3c70a0840 100644 --- a/ethutil/natspec/natspec_test.go +++ b/ethutil/natspec/natspec_test.go @@ -6,41 +6,48 @@ import ( func TestNotice(t *testing.T) { - ns, err := NewNATSpec(` + tx := ` { - "jsonrpc": "2.0", - "method": "eth_call", - "params": [{ - "to": "0x8521742d3f456bd237e312d6e30724960f72517a", - "data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a" - }], - "id": 6 - } - `) + "jsonrpc": "2.0", + "method": "eth_call", + "params": [{ + "to": "0x8521742d3f456bd237e312d6e30724960f72517a", + "data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a" + }], + "id": 6 + } + ` + abi := ` + [{ + "name": "multiply", + "constant": false, + "type": "function", + "inputs": [{ + "name": "a", + "type": "uint256" + }], + "outputs": [{ + "name": "d", + "type": "uint256" + }] + }] + ` + + desc := "Will multiply `a` by 7 and return `a * 7`." + + method := "multiply" + + ns, err := NewNATSpec() if err != nil { t.Errorf("NewNATSpec error %v", err) } - ns.SetABI(` - [{ - "name": "multiply", - "constant": false, - "type": "function", - "inputs": [{ - "name": "a", - "type": "uint256" - }], - "outputs": [{ - "name": "d", - "type": "uint256" - }] - }] - `) - ns.SetDescription("Will multiply `a` by 7 and return `a * 7`.") - ns.SetMethod("multiply") - - notice := ns.Parse() + notice, err := ns.Notice(tx, abi, method, desc) + + if err != nil { + t.Errorf("expected no error got %v", err) + } expected := "Will multiply 122 by 7 and return 854." if notice != expected { @@ -48,4 +55,42 @@ func TestNotice(t *testing.T) { } else { t.Logf("returned notice \"%v\"", notice) } + + notice, err = ns.Notice(tx, abi, method, "Will multiply 122 by \"7\" and return 854.") + + expected = "natspec.js error setting expression: (anonymous): Line 1:41 Unexpected number" + + if err == nil { + t.Errorf("expected error, got nothing (notice: '%v')", err, notice) + } else { + if err.Error() != expected { + t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice) + } + } + + // badDesc := "Will multiply `e` by 7 and return `a * 7`." + // notice, err = ns.Notice(tx, abi, method, badDesc) + + // expected = "natspec.js error evaluating expression: wrong input param in expression ''" + + // if err == nil { + // t.Errorf("expected error, got nothing (notice: '%v')", notice) + // } else { + // if err.Error() != expected { + // t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice) + // } + // } + + notice, err = ns.Notice(tx, abi, "missing_method", desc) + + expected = "natspec.js error evaluating expression: wrong input params in expression 'Will multiply `a` by 7 and return `a * 7`.'" + + if err == nil { + t.Errorf("expected error, got nothing (notice: '%v')", notice) + } else { + if err.Error() != expected { + t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice) + } + } + } -- cgit v1.2.3