I'm trying to help someone calculate the value of 4^3e9.
The problem is that most software don't support numbers this large. Is there an alternative way to calculate this?
My first attempt is to try to divide the number as it is being calculated by looping from 1 to 3e9. If the intermediate result is > 10 then I divide it by it's power of 10, then add this to a variable. In the end I will have a floating point number and the power of 10.
import math
powerof10 = 0
powerof = int(3e9)
# print('powerof', powerof)
initial_value = 4
float_value = initial_value
for i in range(1,powerof): #start from 1 to get correct number of operations
float_value *= initial_value
# print('float value', float_value)
print(i)
if (float_value > 10):
powerof10increment = math.floor(math.log10(float_value))
# print('powerof10', powerof10increment)
powerof10 += powerof10increment
float_value /= 10**powerof10increment
# print('reduced float value', float_value)
print(float_value, ' x 10^', powerof10)
This based on this question here: I want to know what is the value of 4 to the power of 3000000000 (3e+9)
According to the question the number should be in the format 1 x 10^x, so I think only x is required.
Thanks to #NickODell for his comment!
import math
powerof10 = (3e9)*math.log(4)/math.log(10)
print(powerof10)
significand = 10**(powerof10 - math.floor(powerof10))
print(significand, 'x 10^', math.floor(powerof10))
# 9.63578180503111 x 10^ 1806179973
Which matches with the result I get from Wolfram Alpha.
Need help with this assignment, python newbie here, 30 minutes till deadline and i couldn't figure out what's missing. my teacher said it won't work like this.
updated,
if 0 < amount <= 20:
return 0.005, 0
if 20 < amount <= 50:
return 0.893, 0
elif 50 <= amount <= 100:
return 1.000, 0
elif 100 <= amount <= 200:
return 1.900, 0
elif 200 <= amount <= 300:
return 2.800, 0
elif 300 <= amount <= 500:
return 3.500, 0
elif 500 <= amount <= 700:
return 4.000, 0
elif 700 <= amount <= 1000:
return 4.750, 0
else:
return 5.500, 0
I think your problem is here
def has_enough_balance(balance, amount, transaction_type):
return balance >= calculate_fee(amount, transaction_type) + amount
calculate_fee() returns a tuple , in your has_enough_balance() function, you add the amount to it, you cant add a numeric and a tuple
index calculate_fee(amount, transaction_type) to choose which variable you want to use there and your code should be fine
"depends on how and where the function should be used later, it's an abstract function "
you could edit your has_enough_balance() function to
def has_enough_balance(balance, amount, transaction_type, fee_type):
index_dict = {"sender":0, "receiver":1}
return balance >= (calculate_fee(amount, transaction_type)[index_dict[fee_type]]) + amount
basically since you have calculate_fee() returning a tuple, you only want to use one of those values at a time.
you can follow the tuple with [*index of the value you want to use*] to grab the correct value. so I added fee_type as a argument for has_enough_balance() and a dictionary inside to let you say whether you want to use your function for the sender fee or the receiver fee, and the dictionary will match it to its corresponding index, and [index_dict[fee_type]] grabs the correct slice out of calculate_fee()
Your calculate_fee method returns two variables.
In python, when you return multiple variables that's a tuple (example: (0, 0))
But in this block of code
# Checking if client has enough balance before request is sent
def has_enough_balance(balance, amount, transaction_type):
return balance >= calculate_fee(amount, transaction_type) + amount
You try to compare it to a single variable balance and you also try to add it to a single variable amount. These operations are not supported between a tuple, and an int.
From your comment i saw that calculate_fee returns the fee for the sender and the fee for the receiver.
You could edit your has_enough_balance function with a boolean parameter forSender to know if you're calculating the amount for the sender or for the receiver.
You could then use the value of this parameter to know which of the two fees you need to add in your calculation.
# Checking if client has enough balance before request is sent
def has_enough_balance(balance, amount, transaction_type, forSender):
senderFee, receiverFee = calculate_fee(amount, transaction_type)
fee = senderfEE if forSender else receiverFee
return balance >= fee + amount
I use the following snippet for converting a ratio into a percentage:
"{:2.1f}%".format(value * 100)
This works as you would expect. I want to extend this to be more informative in edge cases, where the rounded ratio is 0 or 1, but not exactly.
Is there a more pythonic way, perhaps using the format function, to do this? Alternatively I would add a clause similar to:
if math.isclose(value, 0) and value != 0:
return "< 0.1"
I'd recommend running round to figure out if the string formatting is going to round the ratio to 0 or 1. This function also has the option to choose how many decimal places to round to:
def get_rounded(value, decimal=1):
percent = value*100
almost_one = (round(percent, decimal) == 100) and percent < 100
almost_zero = (round(percent, decimal) == 0) and percent > 0
if almost_one:
return "< 100.0%"
elif almost_zero:
return "> 0.0%"
else:
return "{:2.{decimal}f}%".format(percent, decimal=decimal)
for val in [0, 0.0001, 0.001, 0.5, 0.999, 0.9999, 1]:
print(get_rounded(val, 1))
Which outputs:
0.0%
> 0.0%
0.1%
50.0%
99.9%
< 100.0%
100.0%
I don't believe there is a shorter way to do it. I also wouldn't recommend using math.isclose, as you'd have to use abs_tol and it wouldn't be as readable.
Assuming Python 3.6+, marking exactly zero or exactly 100% could be done with:
>>> for value in (0.0,0.0001,.9999,1.0):
... f"{value:6.1%}{'*' if value == 0.0 or value == 1.0 else ' '}"
...
' 0.0%*'
' 0.0% '
'100.0% '
'100.0%*'
I'm trying to build a function to do internal metric conversion on a wavelength to frequency conversion program and have been having a hard time getting it to behave properly. It is super slow and will not assign the correct labels to the output. If anyone can help with either a different method of computing this or a reason on why this is happening and any fixes that I cond do that would be amazing!
def convert_SI_l(n):
if n in range( int(1e-12),int(9e-11)):
return n/0.000000000001, 'pm'
else:
if n in range(int(1e-10),int(9e-8)):
return n/0.000000001 , 'nm'
else:
if n in range(int(1e-7),int(9e-5)):
return n/0.000001, 'um'
else:
if n in range(int(1e-4),int(9e-3)):
return n/0.001, 'mm'
else:
if n in range(int(0.01), int(0.99)):
return n/0.01, 'cm'
else:
if n in range(1,999):
return n/1000, 'm'
else:
if n in range(1000,299792459):
return n/1000, 'km'
else:
return n , 'm'
def convert_SI_f(n):
if n in range( 1,999):
return n, 'Hz'
else:
if n in range(1000,999999):
return n/1000 , 'kHz'
else:
if n in range(int(1e6),999999999):
return n/1e6, 'MHz'
else:
if n in range(int(1e9),int(1e13)):
return n/1e9, 'GHz'
else:
return n, 'Hz'
c=299792458
i=input("Are we starting with a frequency or a wavelength? ( F / L ): ")
#Error statements
if i.lower() == ("f"):
True
else:
if not i.lower() == ("l"):
print ("Error invalid input")
#Cases
if i.lower() == ("f"):
f = float(input("Please input frequency (in Hz): "))
size_l = c/f
print(convert_SI_l(size_l))
if i.lower() == ("l"):
l = float(input("Please input wavelength (in meters): "))
size_f = ( l/c)
print(convert_SI_f(size_f))
You are using range() in a way that is close to how it is used in natural language, to express a contiguous segment of the real number line, as in in the range 4.5 to 5.25. But range() doesn't mean that in Python. It means a bunch of integers. So your floating-point values, even if they are in the range you specify, will not occur in the bunch of integers that the range() function generates.
Your first test is
if n in range( int(1e-12),int(9e-11)):
and I am guessing you wrote it like this because what you actually wanted was range(1e-12, 9e-11) but you got TypeError: 'float' object cannot be interpreted as an integer.
But if you do this at the interpreter prompt
>>> range(int(1e-12),int(9e-11))
range(0, 0)
>>> list(range(int(1e-12),int(9e-11)))
[]
you will see it means something quite different to what you obviously expect.
To test if a floating-point number falls in a given range do
if lower-bound <= mynumber <= upper-bound:
You don't need ranges and your logic will be more robust if you base it on fixed threshold points that delimit the unit magnitude. This would typically be a unit of one in the given scale.
Here's a generalized approach to all unit scale determination:
SI_Length = [ (1/1000000000000,"pm"),
(1/1000000000, "nm"),
(1/1000000, "um"),
(1/1000, "mm"),
(1/100, "cm"),
(1, "m"),
(1000, "km") ]
SI_Frequency = [ (1, "Hz"), (1000,"kHz"), (1000000,"MHz"), (1000000000,"GHz")]
def convert(n,units):
useFactor,useName = units[0]
for factor,name in units:
if n >= factor : useFactor,useName = factor,name
return (n/useFactor,useName)
print(convert(0.0035,SI_Length)) # 3.5 mm
print(convert(12332.55,SI_Frequency)) # 12.33255 kHz
Each unit array must be in order of smallest to largest multiplier.
EDIT: Actually, range is a function which is generally used in itaration to generate numbers. So, when you write if n in range(min_value, max_value), this function generates all integers until it finds a match or reach the max_value.
The range type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in for loops.
Instead of writing:
if n in range(int(1e-10),int(9e-8)):
return n/0.000000001 , 'nm'
you should write:
if 1e-10 <= n < 9e-8:
return n/0.000000001 , 'nm'
Also keep in mind that range only works on integers, not float.
More EDIT:
For your specific use case, you can define dictionary of *(value, symbol) pairs, like below:
import collections
symbols = collections.OrderedDict(
[(1e-12, u'p'),
(1e-9, u'n'),
(1e-6, u'μ'),
(1e-3, u'm'),
(1e-2, u'c'),
(1e-1, u'd'),
(1e0, u''),
(1e1, u'da'),
(1e2, u'h'),
(1e3, u'k'),
(1e6, u'M'),
(1e9, u'G'),
(1e12, u'T')])
The use the bisect.bisect function to find the "insertion" point of your value in that ordered collection. This insertion point can be used to get the simplified value and the SI symbol to use.
For instance:
import bisect
def convert_to_si(value):
if value < 0:
value, symbol = convert_to_si(-value)
return -value, symbol
elif value > 0:
orders = list(symbols.keys())
order_index = bisect.bisect(orders, value / 10.0)
order = orders[min(order_index, len(orders) - 1)]
return value / order, symbols[order]
else:
return value, u""
Demonstration:
for value in [1e-12, 3.14e-11, 0, 2, 20, 3e+9]:
print(*convert_to_si(value), sep="")
You get:
1.0p
0.0314n
0
2.0
2.0da
3.0G
You can adapt this function to your needs…
I'm processing a.CSV file in python which has a floating type field.
This field has to be modified such that it has at least 4 decimal points and max 8 decimal points of precision.
Example:
input: 5.15
output: 5.1500
input: -12.129999998
output: -12.12999999
What I'm currently doing:
#The field to be modifed is present at index 3 in list temp
dotIndex = temp[3].find('.') + 1
latLen = len(temp[3])-1
if (latLen) - (dotIndex) > 8:
temp[3] = temp[3][0:dotIndex+4]
elif (latLen) - (dotIndex) < 4:
temp[3] = temp[3][0:latLen] + (4 - (latLen - (dotIndex))) * '0'
Is there a better way to write this code to improve performance ?
this should work:
temp[3] = "{:.4f}".format(float(temp[3]))
Considering your comment and the fact you want it truncated, here you go:
n = len(temp[3].split('.')[1])
if n < 4:
temp[3] = "{:.4f}".format(float(temp[3]))
elif n > 8:
parts = temp[3].split('.')
temp[3] = parts[0]+"."+parts[1][:4]
If you're truncating, not rounding, you could use something like this:
def truncate_to_eight(val):
return '{:.8f}'.format((int(val * 10**8))/(10.0**8))
Multiplying by 10 to the power of 8, taking the integer part, and then dividing by 10 to the power 8 gets you the truncation required. Note however, this will always return a value with 8 decimal places - so 5.15 becomes 5.15000000.
You would use this by saying, for example:
rounded = truncate_to_eight(temp[3])