Floor or Ceiling away from zero in Python - python-3.x

Using Python 3, is there a more Pythonic way to floor/ceil as float away from zero than doing this:
import math
def away_from_zero(x):
if x > 0:
return int(math.ceil(x))
else:
return int(math.floor(x))
Is there a better (perhaps more elegant) way to get the nearest integer with greater absolute magnitude?

I would not necessarily consider this more Pythonic, but if you'd like to avoid invoking the math.floor and math.ceiling functions and are looking for something more algebraic, you could do something like this:
def away_from_zero(x):
return int(x // 1 + 2 ** (x > 0) - 1)
As an explanation:
The integer division x // 1 will round down any floating point number, negative or positive, to the nearest integer that's less than x. So 1.5 goes to 1.0 and -1.5 goes to -2.0. This alone solves the problem for negative values and whole numbers, but positive non-integers are off-by-one.
To account for the positive case, we want to offset the result by 1 when x is positive but not when it's negative. You could use conditional logic for this, but if you want to restrict the computation to a single equation, you could also add some term that equals 1 when x is positive and 0 when x is negative. To that end, we have 2 ** (x > 0) - 1. Here, when x is positive, we have
>>> 2 ** True - 1
1
When x is negative, we have
>>> 2 ** False - 1
0
Finally, since integer division of a float returns a float, we cast the result to an int, which gives the desired behavior:
>>> away_from_zero(1.4)
2
>>> away_from_zero(1.6)
2
>>> away_from_zero(-1.4)
-2
>>> away_from_zero(-1.6)
-2

A more elegant way of writing the function you already have would be:
import math
def away_from_zero(x):
return int(math.floor(x) if x > 0 else math.ceil(x))

Related

How to write a function that turns a float into an int and rounds it up instead of down(which is the usual response python gives)

Write a function that takes a float as input and rounds it away from zero, i.e., returns the integer obtained
by rounding up for positive floats and by rounding down for negative floats. The return value should always
be an int object. Consider the example below.
>>> round_away_from_zero(7.2)
8
>>> round_away_from_zero(-3.6)
-4
>>> round_away_from_zero(5.0)
5
Is there a simple iteration that I can solve using this.
I understand it has to do with floor division(i.e x//2) but not sure how to implement
You can use an IF statement. If the number is positive, then we use math.ceil(). Otherwise, we use math.floor().
def round_away_from_zero(n):
if n > 0:
return math.ceil(n)
else:
return math.floor(n)

Trying to end up with two decimal points on a float, but keep getting 0.0

I have a float and would like to limit to just two decimals.
I've tried format(), and round(), and still just get 0, or 0.0
x = 8.972990688205408e-05
print ("x: ", x)
print ("x using round():", round(x))
print ("x using format():"+"{:.2f}".format(x))
output:
x: 8.972990688205408e-05
x using round(): 0
x using format():0.00
I'm expecting 8.98, or 8.97 depending on what method used. What am I missing?
You are using the scientific notation. As glhr pointed out in the comments, you are trying to round 8.972990688205408e-05 = 0.00008972990688205408. This means trying to round as type float will only print the first two 0s after the decimal points, resulting in 0.00. You will have to format via 0:.2e:
x = 8.972990688205408e-05
print("{0:.2e}".format(x))
This prints:
8.97e-05
You asked in one of your comments on how to get only the 8.97.
This is the way to do it:
y = x*1e+05
print("{0:.2f}".format(y))
output:
8.97
In python (and many other programming language), any number suffix with an e with a number, it is power of 10 with the number.
For example
8.9729e05 = 8.9729 x 10^3 = 8972.9
8.9729e-05 = 8.9729 x 10^-3 = 0.000089729
8.9729e0 = 8.9729 x 10^0 = 8.9729
8.972990688205408e-05 8.972990688205408 x 10^-5 = 0.00008972990688205408
8.9729e # invalid syntax
As pointed out by other answer, if you want to print out the exponential round up, you need to use the correct Python string format, you have many choices to choose from. i.e.
e Floating point exponential format (lowercase, precision default to 6 digit)
e Floating point exponential format (uppercase, precision default to 6 digit).
g Same as "e" if exponent is greater than -4 or less than precision, "f" otherwise
G Same as "E" if exponent is greater than -4 or less than precision, "F" otherwise
e.g.
x = 8.972990688205408e-05
print('{:e}'.format(x)) # 8.972991e-05
print('{:E}'.format(x)) # 8.972991E-05
print('{:.2e}'.format(x)) # 8.97e-05
(Update)
OP asked a way to remove the exponent "E" number. Since str.format() or "%" notation just output a string object, break the "e" notation out of the string will do the trick.
'{:.2e}'.format(x).split("e") # ['8.97', '-05']
print('{:.2e}'.format(x).split('e')[0]) # 8.97
If I understand correctly, you only want to round the mantissa/significand? If you want to keep x as a float and output a float, just specify the precision when calling round:
x = round(8.972990688205408e-05,7)
Output:
8.97e-05
However, I recommend converting x with the decimal module first, which "provides support for fast correctly-rounded decimal floating point arithmetic" (see this answer):
from decimal import Decimal
x = Decimal('8.972990688205408e-05').quantize(Decimal('1e-7')) # output: 0.0000897
print('%.2E' % x)
Output:
8.97E-05
Or use the short form of the format method, which gives the same output:
print(f"{x:.2E}")
rount() returns closest multiple of 10 to the power minus ndigits,
so there is no chance you will get 8.98 or 8.97. you can check here also.

Coding Interval Point calculator more efficiently in python

I've been trying to code a function that takes variables a and b which are start and end points and calculate how far to go from a to b as a fraction between 0 and 1. (That fraction is variable x).
The code I have partially works, but it does not always work properly with negative numbers. For example if a = -2 and b = -1 and x = 1 the output should be -1 but I get -2.
I have been solving similar problems thus far using if statements but I don't want to continue like this. Is there a more elegant solution?
def interval_point(a, b, x):
"""Given parameters a, b and x. Takes three numbers and interprets a and b
as the start and end point of an interval, and x as a fraction
between 0 and 1 that returns how far to go towards b, starting at a"""
if a == b:
value = a
elif a < 0 and b < 0 and x == 0:
value = a
elif a < 0 and b < 0:
a1 = abs(a)
b1 = abs(b)
value = -((a1-b1) + ((a1-b1)*x))
else:
value = (a + (b-a)*x)
return(value)
I have played around with the maths somewhat and I have arrived at a much simpler way of solving the problem.
This is what the function now looks like:
def interval_point(a, b, x):
"""Given parameters a, b and x. Takes three numbers and interprets a and b
as the start and end point of an interval, and x as a fraction
between 0 and 1 that returns how far to go towards b, starting at a"""
return((b - a) * x + a)

How to find the cube root of a negative integer such that it does not return NaN?

In Haskell, I have tried to find the cube root of a negative integer, for example, -1, without success.
I have used (-1) ** (1/3), but this returns a NaN. I thought that this might have something to do with type of the (1/3) fraction, but using (1/3 :: Double) yielded no success either.
As a result, my question is how can one find the cube root of -1 using Haskell so that it doesn't return NaN?
For real numbers, the Haskell operator (**) is only defined for negative base (left-hand side) values when the exponent (right-hand side) is integer-valued. If this strikes you as strange, note that the C function pow behaves the same way:
printf("%f\n", pow(-1.0, 1.0/3.0)); // prints "-nan", for me
and so does Python's ** operator:
print((-1.0)**(1.0/3.0))
# gives: ValueError: negative number cannot be raised to fractional power
The problem is partially a mathematical one. The "correct answer" for raising a negative base to a non-integral power is far from obvious. See, for example, this question on the Mathematics SO.
If you only need a cube root that can handle negative numbers, the other answers given should work fine, except that #Istvan's answer should use signum instead of sign, like this:
cbrt x = signum x * abs x ** (1/3)
If you want a more general integral root function for real numbers, be warned that for even n, there are no nth roots of negative numbers that are real, so this is about the best you can do:
-- | Calculate nth root of b
root :: (Integral n, RealFloat b) => n -> b -> b
root n b | odd n && b < 0 = - abs b ** overn
| otherwise = b ** overn
where overn = 1 / fromIntegral n
This gives:
> root 3 (-8)
-2.0
> root 4 (-8)
NaN -- correct, as no real root exists
>
I don't know Haskell, but you can do something like this:
sign(x) * abs(x) ** (1/3)
On ghci I've done something that seems to solve your problem:
let cbrt x = if x < 0 then -((-x) ** (1/3)) else x ** (1/3)
A simple cuberoot function.
As I'm still learning I don't know if this is a proper solution, so please let me know if there's something missing or wrong ;)

math.sqrt function python gives same result for two different values [duplicate]

Why does the math module return the wrong result?
First test
A = 12345678917
print 'A =',A
B = sqrt(A**2)
print 'B =',int(B)
Result
A = 12345678917
B = 12345678917
Here, the result is correct.
Second test
A = 123456758365483459347856
print 'A =',A
B = sqrt(A**2)
print 'B =',int(B)
Result
A = 123456758365483459347856
B = 123456758365483467538432
Here the result is incorrect.
Why is that the case?
Because math.sqrt(..) first casts the number to a floating point and floating points have a limited mantissa: it can only represent part of the number correctly. So float(A**2) is not equal to A**2. Next it calculates the math.sqrt which is also approximately correct.
Most functions working with floating points will never be fully correct to their integer counterparts. Floating point calculations are almost inherently approximative.
If one calculates A**2 one gets:
>>> 12345678917**2
152415787921658292889L
Now if one converts it to a float(..), one gets:
>>> float(12345678917**2)
1.5241578792165828e+20
But if you now ask whether the two are equal:
>>> float(12345678917**2) == 12345678917**2
False
So information has been lost while converting it to a float.
You can read more about how floats work and why these are approximative in the Wikipedia article about IEEE-754, the formal definition on how floating points work.
The documentation for the math module states "It provides access to the mathematical functions defined by the C standard." It also states "Except when explicitly noted otherwise, all return values are floats."
Those together mean that the parameter to the square root function is a float value. In most systems that means a floating point value that fits into 8 bytes, which is called "double" in the C language. Your code converts your integer value into such a value before calculating the square root, then returns such a value.
However, the 8-byte floating point value can store at most 15 to 17 significant decimal digits. That is what you are getting in your results.
If you want better precision in your square roots, use a function that is guaranteed to give full precision for an integer argument. Just do a web search and you will find several. Those usually do a variation of the Newton-Raphson method to iterate and eventually end at the correct answer. Be aware that this is significantly slower that the math module's sqrt function.
Here is a routine that I modified from the internet. I can't cite the source right now. This version also works for non-integer arguments but just returns the integer part of the square root.
def isqrt(x):
"""Return the integer part of the square root of x, even for very
large values."""
if x < 0:
raise ValueError('square root not defined for negative numbers')
n = int(x)
if n == 0:
return 0
a, b = divmod(n.bit_length(), 2)
x = (1 << (a+b)) - 1
while True:
y = (x + n//x) // 2
if y >= x:
return x
x = y
If you want to calculate sqrt of really large numbers and you need exact results, you can use sympy:
import sympy
num = sympy.Integer(123456758365483459347856)
print(int(num) == int(sympy.sqrt(num**2)))
The way floating-point numbers are stored in memory makes calculations with them prone to slight errors that can nevertheless be significant when exact results are needed. As mentioned in one of the comments, the decimal library can help you here:
>>> A = Decimal(12345678917)
>>> A
Decimal('123456758365483459347856')
>>> B = A.sqrt()**2
>>> B
Decimal('123456758365483459347856.0000')
>>> A == B
True
>>> int(B)
123456758365483459347856
I use version 3.6, which has no hardcoded limit on the size of integers. I don't know if, in 2.7, casting B as an int would cause overflow, but decimal is incredibly useful regardless.

Resources