Implementation of excel's ROUND function - excel

How would you implement a ROUND function:
ROUND(value, number of digits)
pi=3.14159265358979323
so, for example, ROUND(pi, 3) = 3.142
if you had these functions at your disposal:
AINT - truncates a value to a whole number
ANINT - calculates the nearest whole number
NINT - returns the nearest integer to the argument
or never minding the above functions, how is floating ROUND done at all ?

If you don't need to worry about overflow, here's how:
ROUND(value, nod) = NINT(value * POWER(10, nod)) / POWER(10, nod)
Otherwise you need to take care of the integer part and the float part separately.

I would assume, excuse my pseudo-code
function Round(value, num){
numsToSave = POWER(10, num);
value *= numsToSave ; //Get the numbers we don't want rounded on the left side of the floating point
value = AINT( ANINT(value) );
value /= numsToSave;
return value;
}
or
function Round(value, num){
numsToSave = POWER(10, num);
value *= numsToSave ; //Get the numbers we don't want rounded on the left side of the floating point
value = NINT(value);
value /= numsToSave;
return value;
}

Related

How to get first 4 digits after the 0s in a decimal but keeping 0s • Python

I need the first 4 digits after the front 0s in a decimal while also keeping the 0s in the output without getting scientific notation.
Would like to take
0.0000000000000000000000634546534
and get
0.00000000000000000000006345 but not
6.345e-23.
But would also like to take
231.00942353246
and get
231.009423.
Thank you.
Here's one way using the decimal module.
import decimal
example = 0.0000000000000000000000634546534
x = decimal.Decimal(example)
sign = x.as_tuple().sign
digits = x.as_tuple().digits
exponent = x.as_tuple().exponent
figs = 4
result = decimal.Decimal((sign, digits[:figs], len(digits)+(exponent)-figs))
precision = -1 * (len(digits) + (exponent) - figs) # for this example: -1 * (99 + (-121) - 4)
print("{:.{precision}f}".format(float(result), precision=precision))
Result:
0.00000000000000000000006345
Note that Decimal stores 99 digits because of floating point imprecision. The example variable holds a float value (due to the initializer value) that is inherently imprecise. There is no way around this, unless you are able to represent the original float value as a string, that you can use to initialize the example variable.
There are cases, where the 4th digit shown will be wrong, because in the floating point representation that digit is represented as one lesser and the next digit is a 9, for example. To fix, this, we grab one more digit as well to use for rounding. This should work in most cases, as the imprecision should be within the nearest rounding threshold.
result = decimal.Decimal((0, digits[:figs + 1], len(digits)+(exponent)-figs-1))
Lastly, to handle the case where there are numbers before the decimal, we can simply store it, remove it, and re-add it:
whole_number_part = int(example)
example -= whole_number_part
...
result += whole_number_part
Altogether, we get:
import decimal
example = 231.00942353246
whole_number_part = int(example)
example -= whole_number_part
x = decimal.Decimal(example)
sign = x.as_tuple().sign
digits = x.as_tuple().digits
exponent = x.as_tuple().exponent
figs = 4
result = decimal.Decimal((0, digits[:figs + 1], len(digits)+(exponent)-figs-1))
result += whole_number_part
precision = -1 * (len(digits) + (exponent) - figs)
print("{:.{precision}f}".format(float(result), precision=precision))
Result:
231.009423

simple rounding down decimal places

I wrote a simple function to round down a number based on a certain number of decimal places by using the built-in round function and subtracting the last decimal by 1 if it rounds up.
def rounddown(number, places):
rounded = round(number, places)
if rounded > number:
string = '1'
for x in range(places):
string = string + '0'
return rounded - (1/float(string))
else:
return rounded
my problem is sometimes the results end up being a number like this:
rounddown(4.555756, 5)
4.555750000000001
Could someone explain to me exactly what is going on here? I think it may have something to do with floating point math inaccuracy?
Thank you
The issue is basically Floating point operations ,to avoid the problem
Please use the decimal library as shown below
from decimal import Decimal
def rounddown(number, places):
rounded = round(number, places)
if rounded > number:
string = '1'
for x in range(places):
string = string + '0'
return Decimal(str(rounded))-1/Decimal(string)
else:
return rounded

Robust linear interpolation

Given two segment endpoints A and B (in two dimensions), I would like to perform linear interpolation based on a value t, i.e.:
C = A + t(B-A)
In the ideal world, A, B and C should be collinear. However, we are operating with limited floating-point here, so there will be small deviations. To work around numerical issues with other operations I am using robust adaptive routines originally created by Jonathan Shewchuk. In particular, Shewchuk implements an orientation function orient2d that uses adaptive precision to exactly test the orientation of three points.
Here my question: is there a known procedure how the interpolation can be computed using the floating-point math, so that it lies exactly on the line between A and B? Here, I care less about the accuracy of the interpolation itself and more about the resulting collinearity. In another terms, its ok if C is shifted around a bit as long as collinearity is satisfied.
The bad news
The request can't be satisfied. There are values of A and B for which there is NO value of t other than 0 and 1 for which lerp(A, B, t) is a float.
A trivial example in single precision is x1 = 12345678.f and x2 = 12345679.f. Regardless of the values of y1 and y2, the required result must have an x component between 12345678.f and 12345679.f, and there's no single-precision float between these two.
The (sorta) good news
The exact interpolated value, however, can be represented as the sum of 5 floating-point values (vectors in the case of 2D): one for the formula's result, one for the error in each operation [1] and one for multiplying the error by t. I'm not sure if that will be useful to you. Here's a 1D C version of the algorithm in single precision that uses fused multiply-add to calculate the product error, for simplicity:
#include <math.h>
float exact_sum(float a, float b, float *err)
{
float sum = a + b;
float z = sum - a;
*err = a - (sum - z) + (b - z);
return sum;
}
float exact_mul(float a, float b, float *err)
{
float prod = a * b;
*err = fmaf(a, b, -prod);
return prod;
}
float exact_lerp(float A, float B, float t,
float *err1, float *err2, float *err3, float *err4)
{
float diff = exact_sum(B, -A, err1);
float prod = exact_mul(diff, t, err2);
*err1 = exact_mul(*err1, t, err4);
return exact_sum(A, prod, err3);
}
In order for this algorithm to work, operations need to conform to IEEE-754 semantics in round-to-nearest mode. That's not guaranteed by the C standard, but the GNU gcc compiler can be instructed to do so, at least in processors supporting SSE2 [2][3].
It is guaranteed that the arithmetic addition of (result + err1 + err2 + err3 + err4) will be equal to the desired result; however, there is no guarantee that the floating-point addition of these quantities will be exact.
To use the above example, exact_lerp(12345678.f, 12345679.f, 0.300000011920928955078125f, &err1, &err2, &err3, &err4) returns a result of 12345678.f and err1, err2, err3 and err4 are 0.0f, 0.0f, 0.300000011920928955078125f and 0.0f respectively. Indeed, the correct result is 12345678.300000011920928955078125 which can't be represented as a single-precision float.
A more convoluted example: exact_lerp(0.23456789553165435791015625f, 7.345678806304931640625f, 0.300000011920928955078125f, &err1, &err2, &err3, &err4) returns 2.3679010868072509765625f and the errors are 6.7055225372314453125e-08f, 8.4771045294473879039287567138671875e-08f, 1.490116119384765625e-08f and 2.66453525910037569701671600341796875e-15f. These numbers add up to the exact result, which is 2.36790125353468550173374751466326415538787841796875 and can't be exactly stored in a single-precision float.
All numbers in the examples above are written using their exact values, rather than a number that approximates to them. For example, 0.3 can't be represented exactly as a single-precision float; the closest one has an exact value of 0.300000011920928955078125 which is the one I've used.
It might be possible that if you calculate err1 + err2 + err3 + err4 + result (in that order), you get an approximation that is considered collinear in your use case. Perhaps worth a try.
References
[1] Graillat, Stef (2007). Accurate Floating Point Product and Exponentiation.
[2] Enabling strict floating point mode in GCC
[3] Semantics of Floating Point Math in GCC

default scale of bigdecimal in groovy

What is the default scale of BigDecimal in groovy? And Rounding?
So when trying to do calculations:
def x = 10.0/30.0 //0.3333333333
def y = 20.0/30.0 //0.6666666667
Base on this, I can assume that it uses scale 10 and rounding half up.
Having trouble finding an official documentation saying that though.
You can find it in the official documentation: The case of the division operator
5.5.1. The case of the division operator
The division operators / (and /= for division and assignment) produce
a double result if either operand is a float or double, and a
BigDecimal result otherwise (when both operands are any combination of
an integral type short, char, byte, int, long, BigInteger or
BigDecimal).
BigDecimal division is performed with the divide() method if the
division is exact (i.e. yielding a result that can be represented
within the bounds of the same precision and scale), or using a
MathContext with a precision of the maximum of the two operands'
precision plus an extra precision of 10, and a scale of the maximum of
10 and the maximum of the operands' scale.
And check it in BigDecimalMath.java:
public Number divideImpl(Number left, Number right) {
BigDecimal bigLeft = toBigDecimal(left);
BigDecimal bigRight = toBigDecimal(right);
try {
return bigLeft.divide(bigRight);
} catch (ArithmeticException e) {
// set a DEFAULT precision if otherwise non-terminating
int precision = Math.max(bigLeft.precision(), bigRight.precision()) + DIVISION_EXTRA_PRECISION;
BigDecimal result = bigLeft.divide(bigRight, new MathContext(precision));
int scale = Math.max(Math.max(bigLeft.scale(), bigRight.scale()), DIVISION_MIN_SCALE);
if (result.scale() > scale) result = result.setScale(scale, BigDecimal.ROUND_HALF_UP);
return result;
}
}

How to truncate floating point number in jscript?

How to truncate float value in Jscript?
eg.
var x = 9/6
Now x contains a floating point number and it is 1.5.
I want to truncate this and get the value as 1
x = Math.floor(x)
This will round the value of x down to the nearest integer below.
Math.round() should achieve what you're looking for, but of course it'll round 1.5 to 2. If you always want to round down to the nearest integer, use Math.floor():
var x = Math.floor(9 / 6);
Math.floor() only works as the OP intended when the number is positive, as it rounds down and not towards zero. Therefore, for negative numbers, Math.ceil() must be used.
var x = 9/6;
x = (x < 0 ? Math.ceil(x) : Math.floor(x));
Another solution could be:
var x = parseInt(9 / 6);
Wscript.StdOut.WriteLine(x); // returns 1
the main purpose of the parseInt() function is to parse strings to integers. So I guess it might be slower than Math.floor() and methods as such.

Resources