Banana.SDecimal

Documentation •
In this article

The Banana.SDecimal (String Decimal) provides math functions to do precise decimal math calculation. It takes numeric strings as input and return a numeric string .

All data, including numbers, are stored in the Banana Accounting Table as strings. 

  • It overcomes the rounding problem typical of Javasctipt float type.
  • In order to avoid rounding errors, the Banana.SDecimal class should be used to perform mathematical calculation between number expressed as strings, instead of the Javascript floating point numeric.

Main characteristics

  • Use decimal string in the form of '10.00' or '-10' as argument and return value
    • '.' is interpreted as the decimal separator
    • thousand separator are not allowed
  • Negative numbers have a minus "-" sign preceding the number.
  • Have up to 34 digits of numeric precision
  • Do accurate decimal rounding
  • Within the table, the value amounts and numeric columns are already in SDecimal format.

Banana.SDecimal examples

You can use these functions instead of the javascript Number that uses floating point arithmetic and are not very suitable for accounting calculations due to the rounding differences.

Basic examples

// sum '6.50+3.50' and use the default 2 decimal digits
var r = Banana.SDecimal.add('6.50', '3.50');   // return '10.00'

// divide '10/2' and use the default 2 decimal digits
var r = Banana.SDecimal.divide('10', '2');     // return '5.00'

// divide '10/2' and use 5 decimal digits
var r = Banana.SDecimal.divide('10', '2', {'decimals':5});     // return '5.00000'

Sum of two amounts

// Example input text amounts
var textAmount1 = "1234.56";  // A valid number in string format
var textAmount2 = "-789.12";  // Another valid number in string format

// Perform the addition using Banana.SDecimal.add
var sum = Banana.SDecimal.add(textAmount1, textAmount2);

Sum of two amounts in local number format

// Example input text amounts
var textAmount1 = Banana.Converter.toInternalNumberFormat("1'234,56", ",");  // A valid number in local format
var textAmount2 = Banana.Converter.toInternalNumberFormat("-789,12", ",");   // Another valid number in local format

// Perform the addition using Banana.SDecimal.add
var sum = Banana.SDecimal.add(textAmount1, textAmount2);

Check if an amount is negative

if (Banana.SDecimal.sign('-789.12') < 0) {
  // amount is negative
}

Use SDecimal with amount values from table

Within the table, the value amounts and numeric columns are already in SDecimal format. These values don't need to be converted to float.

The example that calculates the total of debits and credits, and the balance of the account in the row "0" of the table.

function calculateBalanceTotal() {
    let accountsTable = Banana.document.table("Accounts"); // Reads from table Accounts
    let row = accountsTable.row(0); // take the first row (index 0) or the table
    let opening = row.value("Opening");  // row.value("column_name_xml") already returns the text in Banana.SDecimal format
    let debit = row.value("Debit");  // row.value("column_name_xml") already returns the text in Banana.SDecimal format
    let credit = row.value("Credit");  // row.value("column_name_xml") already returns the text in Banana.SDecimal format
    let total = Banana.SDecimal.subtract(debit, credit);
    let balance = Banana.SDecimal.add(total, opening);
    return balance;
}

Use SDecimal to sum the balance column

Within the table, the value amounts and numeric columns are already in SDecimal format.

The example sums all balances of normal accounts.

function calculateBalanceTotal() {

    // Get the "Accounts" table
    let accountsTable = Banana.document.table("Accounts");
    let totalBalance = 0;

    for (let i = 0; i < accountsTable.rowCount; i++) {
        let row = accountsTable.row(i);
        let account = row.value("Account");
        
        // Only rows with normal accounts (not cost centers or segments)
        if (account && !account.startsWith(".") && !account.startsWith(",") && !account.startsWith(";") && !account.startsWith(":")) {
           let balance = row.value("Balance"); // get the balance value already in SDecimal format
           totalBalance = Banana.SDecimal.add(totalBalance, balance); // Add the balance amounts
        }
    }
    return totalBalance;
}

 

Rounding context

Functions can be passed a rounding context that specify the rounding properties:

  • decimals is the number of decimal digits (default value is 2)
    • null returns the value unrounded.
    • '0' returns with no decimals.
    • '1' to '33' returns the value with the indicated number of decimals.
  • mode is the rounding mode (default value is HALF_UP)
    • Banana.SDecimal.HALF_UP the amount is rounded to the nearest. The 0.5 are rounded up.
    • Banana.SDecimal.HALF_EVEN the amount is rounded to the nearest. The 0.5 are rounded up or down based on the preceding digit.

If the rounding context is omitted no rounding is done.

Rounding context of the accounting file

All Banana document files have a rounding context that can be retrieved with the property Banana.document.rounding (see Banana.document).

Examples:

// no context
var r = Banana.SDecimal.divide('10', '3'); // return '3.3333333333333333333333333'

// with context
var context = {'decimals' : 4, 'mode' : Banana.SDecimal.HALF_UP};
var r = Banana.SDecimal.divide('10', '3', context);        // return '3.3333'
var r = Banana.SDecimal.divide('10', '3', {'decimals':0}); // return '3'

// use the rounding property (accounting file 2 decimals)
var r = Banana.SDecimal.divide('10', '3', Banana.document.rounding); // return '3.33'

Methods

The list of all available methods for the SDecimal class is listed below.

abs(value1, [, roundingContext])

Returns the absolute value of value1, removing its sign. The result is optionally rounded based on the specified roundingContext.

Parameters:

  • value1 (string): The numeric value (as a string) whose absolute value is to be calculated.
  • roundingContext (optional): A rounding specification (e.g., number of decimal places). If provided, the result will be rounded accordingly.

Returns:

  • A string representing the absolute value of value1, optionally rounded.
var r = Banana.SDecimal.abs('-10') // return '10.00'

 add(value1, value2 [, roundingContext])

Returns the sum of value1 and value2.

var r = Banana.SDecimal.add('6.50', '3.50'); // return '10.00'

compare(value1, value2)

Returns an integer value:

  • 1 if value1 > value2
  • 0 if value1 = value2
  • -1 if value1 < value2
Banana.SDecimal.compare('3.50', '2'); // return '1'
Banana.SDecimal.compare('3.00', '3'); // return '0'

divide(value1, value2 [, roundingContext])

Returns value1 divided by value2.

var r = Banana.SDecimal.divide('6', '3'); // return '2.00'

isZero(value)

Returns a boolean

  • true if value is zero
  • false if value is not zero
var r = Banana.SDecimal.isZero('3.00'); // return 'false'

max(value1, value2 [, roundingContext])

Returns the max between value1 and value2.

var r = Banana.SDecimal.max('6', '3'); // return '6.00'

min(value1, value2 [, roundingContext])

Returns the min between value1 and value2.

var r = Banana.SDecimal.min('6', '3'); // return '3.00'

multiply(value1, value2 [, roundingContext])

Returns value1 multiplied by value2.

var r = Banana.SDecimal.multiply('6', '3'); // return '18.00'

remainder(value1, value2 [, roundingContext])

Divide value1 by value2 and returns the reminder.

var r = Banana.SDecimal.reminder('10', '3'); // return '1.00'

round(value1, [, roundingContext])

Returns value1 round to the spcified rounding context.

var r = Banana.SDecimal.round('6.123456'); // no context no rounding 
r = Banana.SDecimal.round('6.123456', {'decimals':2}); // return '6.12'

roundNearest(value1, nearest, [, roundingContext])

Returns value1 round to the specified minimal amount.

var r = Banana.SDecimal.roundNearest('6.17', '0.1'); // return '6.1'
r = Banana.SDecimal.roundNearest('6.17', '0.05', {'decimals':2}); // return '6.15'

invert(value, [, roundingContext])

The invert function reverses the sign of a numeric value. If the input is positive, it returns the corresponding negative value. If the input is negative, it returns the corresponding positive value. The result is optionally rounded based on the provided roundingContext.

Parameters:

  • value (string): The numeric value (as a string) whose sign is to be inverted.
  • roundingContext (optional): A rounding specification (e.g., number of decimal places). If provided, the result will be rounded accordingly.

Returns:

  • A string representing the value with its sign inverted, optionally rounded.
var a = Banana.SDecimal.invert('5'); //return '-5'
var b = Banana.SDecimal.invert('-2.50'); //return '2.50'

sign(value)

Returns an integer value

  • 1 if value > 0
  • 0 if  value = 0
  • -1 if value < 0
var r = Banana.SDecimal.sign('-5'); // return '-1'

 subtract(value1, value2 [, roundingContext])

Subtract value2 from value1 and returns the result.

var r = Banana.SDecimal.subtract('10', '3'); // return '7.00'

 

Locale conversion

To convert to and from the locale format use the Banana.Converter functions

  • Banana.Converter.toInternalNumberFormat(value [, decimals, convZero])
  • Banana.Converter.toLocaleNumberFormat(value [, decimalSeparator])
var sum = Banana.SDecimal.add('10000', '2000'); // return '12000.00'
var printValue = Banana.Converter.toLocaleNumberFormat(sum); // return "12'000.00"

 

Help us improve the documentation

We welcome feedback on how to improve this page.

Tell us what theme needs a better explanation or how to clarify a topic.

Share this article: Twitter | Facebook | LinkedIn | Email