String Formatting with Decimal Number Python - python-3.x

I am working on building a report. One figure on the report needs to be expressed in millions. I wrote some basic formatters to handle various types of formatting that need to be consistent throughout the report. To do this, I use lambda functions and string formatting. The two functions are below. One is to round, the other to format.
formatter_round = lambda x: 0 if (x is None or x is bool) else round(x/1000000,1)
formatter_dollar = lambda x: '${:,.1}'.format(0) if (x is None or x == 0) else ('${:,.1}'.format(x) if x >= 0 else '$({:,.1})'.format(abs(x)))
Now comes the problem. See my example below.
I am dealing with two numbers, a = 350000 and b = 850000.
For a everything works as I'd expect. The float isn't necessarily correct when rounded ( not "what I'd expect", but understandable behavior), but the decimal is correct.
a = 350000
formatter_dollar(formatter_round(a))
Out[89]: '$0.3'
a = Decimal(a)
formatter_dollar(formatter_round(a))
Out[91]: '$0.4'
When I run the same example with b, however, this breaks down.
b = 850000
formatter_dollar(formatter_round(b))
Out[93]: '$0.8'
b = Decimal(b)
formatter_dollar(formatter_round(b))
Out[95]: '$0.8'
My question is, how can I properly round and display numbers?
I thought my issue was floating point numbers, and a seemed to confirm that. Then when I ran the same with b, I realized that isn't the case.

Related

Why does this n choose r python code not work?

These 2 variations of n choose r code got different answer although followed the correct definition
I saw that this code works,
import math
def nCr(n,r):
f = math.factorial
return f(n) // f(r) // f(n-r)
But mine did not:
import math
def nCr(n,r):
f = math.factorial
return int(f(n) / (f(r) * f(n-r)))
Use test case nCr(80,20) will show the difference in result. Please advise why are they different in Python 3, thank you!
No error message. The right answer should be 3535316142212174320, but mine got 3535316142212174336.
That's because int(a / b) isn't the same as a // b.
int(a / b) evaluates a / b first, which is floating-point division. And floating-point numbers are prone to inaccuracies, roundoff errors and the like, as .1 + .2 == 0.30000000000000004. So, at some point, your code attempts to divide really big numbers, which causes roundoff errors since floating-point numbers are of fixed size, and thus cannot be infinitely precise.
a // b is integer division, which is a different thing. Python's integers can be arbitrarily huge, and their division doesn't cause roundoff errors, so you get the correct result.
Speaking about floating-point numbers being of fixed size. Take a look at this:
>>> import math
>>> f = math.factorial
>>> f(20) * f(80-20)
20244146256600469630315959326642192021057078172611285900283370710785170642770591744000000000000000000
>>> f(80) / _
3.5353161422121743e+18
The number 3.5353161422121743e+18 is represented exactly as shown here: there is no information about the digits after the last 3 in 53...43 because there's nowhere to store it. But int(3.5353161422121743e+18) must put something there! Yet it doesn't have enough information. So it puts whatever it wants to so that float(int(3.5353161422121743e+18)) == 3.5353161422121743e+18.

Algorithm: find two positive integers whose difference is minimized and whose product is known

Some background...
I am currently building a macro that will estimate the cost of an injection molding tool. These tools have cavities which are filled with plastic. The number of cavities a tool has is the number of parts that will be formed.
So far my program will determine the minimum number of cavities a tool can have based on customer demand. This number is always even. The tool should have an even number of cavities. Given the bounding length and width of a cavity, and setting a limit to how much space the cavities can occupy within the tool, I need my program to calculate the combination of number of cavities along the length and width whose difference is minimized and whose product is equal to the total number of minimum cavities the tool should have.
I am programming my macro is SolidWorks VBA. I first constructed this problem in Excel and used the solver tool. But, I am unable to find a way to reference the Excel Solver Tool in SolidWorks to automate this optimization problem. I am hoping to find a clever set of equations that can solve this specific problem for me. But if someone else has a better idea of what to use, that would be awesome.
Rephrasing in an optimization format...
Variables
x = number of cavities along width of tool
y = number of cavities along length of tool
z = suggested number of total cavities
Objective Function
Minimize x - y
Such that
x * y = z
x >= 1
y >= 1
x <= y
x is an integer
y is an integer
Example
My macro says that in order to meet demand, our tool needs to have at least 48 cavities. Find the number of cavities along the length and width of the tool such that the difference is minimized and the product is equal to 48. Ideally in this case the macro would return x = 6 and y = 8.
Thanks!
Just to clarify, in the question did you actually mean to Min y-x rather than Min x-y? Otherwise there is a naïve solution taking x = 1 and y = z. Min x - y = 1-z.
I don't program in VBA but here is the idea.
Since x and y are positive integers and there product is z, with x <= y. You can essentially start with x = floor(sqrt(z)) and decrement until x = 1.
For each x, check if there exists an integer y such that x * y = z. If there is, break the loop and that's the pair you are looking for. Otherwise continue until x = 1
If you need any pseudo code so you can translate it into VBA. Here it is
int x, y;
for (x = floor(sqrt(z)); x >= 1; --x)
{
y = z / x;
if (x * y == z)
break;
}
I think you can just test out a few examples. No fancy algorithm is needed.
If you relax the condition to be 2 numbers, x and y, whose product is z and with a minimum difference, then the answer is SQRT(z).
That is not an integer that meets your needs (in general). However, you can then try integers around the square root to see if they divide z. The first one you hit (i.e. minimum difference from SQRT(z)) should have the minimum difference.
If you relax the condition to be |z - x * y| is minimized, then I would recommend testing the numbers around sqrt(z). You need to check two cases -- the floor and ceiling of the square root (and the appropriate other number).
Just in case someone is needs something similar to this in the future, but can't figure out the pseudo-code I went ahead wrote it up. I wasn't sure how to output it as two values so I just threw them together as a string for the user to see.
Option Explicit
Function Factors(ByVal Test As Long) As String
Dim Val As Long
Dim i As Long
Val = Test
i = Int(Sqr(Val))
While Val / i >= 2
If Int(Val / i) * i = Val Then
Factors = i & " & " & Val / i
Exit Function
End If
i = i - 1
Wend
End Function

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.

How do I compare large numbers to small numbers in python 3?

I have to use the math.exp() function to get the following value for x which is converted to scientific notation. However, when trying to compare to see if this number is greater than y, python thinks it is less than.
x = 4.0686596698143466e+186
y = 59425800000000000000000
if x >= y:
print:("x is greater than y")
I realize there are methods to turn very large numbers into smaller int but I feel that route is a little more complicated and above my learning curve than necessary. I just need a way to see if x > y and also curious why python doesn't support the comparison. Converting y to scientific notation using decimal only turns it into a string.
Disclaimer: still a beginner

Statistical Analysis Error? python 3 proof read please

The code below generates two random integers within range specified by argv, tests if the integers match and starts again. At the end it prints some stats about the process.
I've noticed though that increasing the value of argv reduces the percentage of tested possibilities exponentially.
This seems counter intuitive to me so my question is, is this an error in the code or are the numbers real and if so then what am I not thinking about?
#!/usr/bin/python3
import sys
import random
x = int(sys.argv[1])
a = random.randint(0,x)
b = random.randint(0,x)
steps = 1
combos = x**2
while a != b:
a = random.randint(0,x)
b = random.randint(0,x)
steps += 1
percent = (steps / combos) * 100
print()
print()
print('[{} ! {}]'.format(a,b), end=' ')
print('equality!'.upper())
print('steps'.upper(), steps)
print('possble combinations = {}'.format(combos))
print('explored {}% possibilitys'.format(percent))
Thanks
EDIT
For example:
./runscrypt.py 100000
will returm me something like:
[65697 ! 65697] EQUALITY!
STEPS 115867
possble combinations = 10000000000
explored 0.00115867% possibilitys
"explored 0.00115867% possibilitys" <-- This number is too low?
This experiment is really a geometric distribution.
Ie.
Let Y be the random variable of the number of iterations before a match is seen. Then Y is geometrically distributed with parameter 1/x (the probability of generating two matching integers).
The expected value, E[Y] = 1/p where p is the mentioned probability (the proof of this can be found in the link above). So in your case the expected number of iterations is 1/(1/x) = x.
The number of combinations is x^2.
So the expected percentage of explored possibilities is really x/(x^2) = 1/x.
As x approaches infinity, this number approaches 0.
In the case of x=100000, the expected percentage of explored possibilities = 1/100000 = 0.001% which is very close to your numerical result.

Resources