I encountered a floating-point imprecision issue in Awk that I can't solve. Is there a simple solution to it?
Here is my example Awk script to replicate the floating-point imprecision issue.
BEGIN {
print "PREC = " PREC
print "OFMT = " OFMT
print "CONVFMT = " CONVFMT
a = 1.2 + 3.4
b = 8.9 - 4.3
print "a = " a
print "b = " b
if ( a == b )
print "a == b"
else
print "a != b"
c = 3.2 + 5.4
d = 9.8 - 1.2
print "c = " c
print "d = " d
if ( c == d )
print "c == d"
else
print "c != d"
}
Here is the output of the above script.
PREC = 53
OFMT = %.6g
CONVFMT = %.6g
a = 4.6
b = 4.6
a != b
c = 8.6
d = 8.6
c == d
Why is a != b even if both have same values? Yet, c == d works properly.
I assume Awk has some internal floating-point imprecision. FYI, I'm using Gawk 4.1.4.
I tried various values for PREC, OFMT & CONVFMT, but failed to find ones that would work.
E.g. Changed OFMT & CONVFMT to %.6f:
PREC = 53
OFMT = %.6f
CONVFMT = %.6f
a = 4.600000
b = 4.600000
a != b
c = 8.600000
d = 8.600000
c == d
E.g. Changed PREC to 16:
PREC = 16
OFMT = %.6g
CONVFMT = %.6g
a = 4.6
b = 4.6
a != b
c = 8.6
d = 8.6
c == d
Basically, I'm hoping for some settings inside BEGIN, instead of changing every expression where floating-point arithmetic & comparison are, since my actual Awk script is much longer than the example above.
E.g. I rather not having to use sprintf for each arithmetic & comparison expression, or to convert each input number to integer after scaling by 1e6 & convert each output number by 1e-6. Such approach would be very daunting.
FYI, floating-point numbers in input files will have maximum 6 decimal points, but they may be without decimal points, i.e. they range from 0 to 6 decimal points.
Thank you for your help.
HN
Here the higher precision is working against you. Since some of the decimal values cannot be represented exactly in binary you're just pushing the limits of number equivalence to higher precision numbers which will not be satisfied.
For example for 53 digit precision, you get
1.2 => 1.199999999999999955591079014993738383054733
3.4 => 3.399999999999999911182158029987476766109467
8.9 => 8.900000000000000355271367880050092935562134
4.3 => 4.299999999999999822364316059974953532218933
a = 4.599999999999999644728632119949907064437866
b = 4.600000000000000532907051820075139403343201
a != b
3.2 => 3.200000000000000177635683940025046467781067
5.4 => 5.400000000000000355271367880050092935562134
9.8 => 9.800000000000000710542735760100185871124268
1.2 => 1.199999999999999955591079014993738383054733
c = 8.600000000000001421085471520200371742248535
d = 8.600000000000001421085471520200371742248535
c==d
My suggestion is set the PREC to a more reasonable value (based on your input data precision). I think 10 would be a good tradeoff with minimal code change.
'BEGIN{PREC=10; ...
NB. If you ask why c,d matches, notice that they are all fractions are multiples of 0.2, whereas a,b has a 0.3.
Floating point numbers aren't exact, the answers displayed are rounded off and aren't exactly what the floating point representation is, but the test for equality counts every bit of the results.
As an example, try dividing 1 by 3 with pencil and paper, you get 0.3333333... until you run out of paper. Now multiplying should give you 1.0, right? No, you'll get 0.9999999999...
Similarly, floating point can't exactly represent 0.1.
What's generally done is to compare equality to be within a certain limit, called an "epsilon".
if absolute value of (a - b) < 0.0000001
then print "Equal"
https://www.youtube.com/watch?v=PZRI1IfStY0
GNU Awk's User's Guide - Setting precision says
If you need to represent a floating-point constant at a higher
precision than the default and cannot use a command-line assignment to
PREC, you should either specify the constant as a string, or as a
rational number, whenever possible.
Related
I don't even know if something like this is possible, but:
Let us say we have three numbers:
A = 6
B = 7.5
C = 24
I would like to find a few evenly spaced common multiples of these numbers between 0 and 2.
So the requirement is: one_of_these_numbers / common_multiple = an_integer (or almost an integer with a particular tolerance)
For example, a good result would be [0.1 , 0.5 , 1 , 1.5]
I have no idea if this is possible, because one can not iterate through a range of floats, but is there a smart way to do it?
I am using python, but a solution could be represented in any language of your preference.
Thank you for your help!
While I was writing my question, I actually came up with an idea for the solution.
To find common divisors using code, we have to work with integers.
My solution is to multiply all numbers by a factor = 1, 10, 100, ...
so that we can act as if they are integers, find their integer common divisors, and then redivide them by the factor to get a result.
Better explained in code:
a = 6
b = 7.5
c = 24
# Find a few possible divisors between 0 and 2 so that all numbers are divisible
by div.
# We define a function that finds all divisors in a range of numbers, supposing
all numbers are integers.
def find_common_divisors(numbers, range_start, range_end):
results = []
for i in range(range_start + 1, range_end + 1):
if all([e % i == 0 for e in numbers]):
results.append(i)
return results
def main():
nums = [a, b, c]
range_start = 0
range_end = 2
factor = 1
results = [1]
while factor < 11:
nums_i = [e * factor for e in nums]
range_end_i = range_end * factor
results += [e / factor for e in find_common_divisors(nums_i, range_start, range_end_i)]
factor *= 10
print(sorted(set(results)))
if __name__ == '__main__':
main()
For these particular numbers, I get the output:
[0.1, 0.3, 0.5, 1, 1.5]
If we need more results, we can adjust while factor < 11: to a higher number than 11 like 101.
I am curious to see if I made any mistake in my code.
Happy to hear some feedback.
Thank you!
I am trying to fit 3 numbers inside 1 number.But numbers will be only between 0 and 11.So their (base) is 12.For example i have 7,5,2 numbers.I come up with something like this:
Three numbers into One number :
7x12=84
84x5=420
420+2=422
Now getting back Three numbers from One number :
422 MOD 12 = 2 (the third number)
422 - 2 = 420
420 / 12 = 35
And i understanded that 35 is multiplication of first and the second number (i.e 7 and 5)
And now i cant get that 7 and 5 anyone knows how could i ???
(I started typing this answer before the other one got posted, but this one is more specific to Arduino then the other one, so I'm leaving it)
The code
You can use bit shifting to get multiple small numbers into one big number, in code it would look like this:
int a, b, c;
//putting then together
int big = (a << 8) + (b << 4) + c;
//separating them again
a = (big >> 8) & 15;
b = (big >> 4) & 15;
c = big & 15;
This code only works when a, b and c are all in the range [0, 15] witch appears to be enough for you case.
How it works
The >> and << operators are the bitshift operators, in short a << n shifts every bit in a by n places to the left, this is equivalent to multiplying by 2^n. Similarly, a >> n shifts to to the right. An example:
11 << 3 == 120 //0000 1011 -> 0101 1000
The & operator performs a bitwise and on the two operands:
6 & 5 == 4 // 0110
// & 0101
//-> 0100
These two operators are combined to "pack" and "unpack" the three numbers. For the packing every small number is shifted a bit to the left and they are all added together. This is how the bits of big now look (there are 16 of them because ints in Arduino are 16 bits wide):
0000aaaabbbbcccc
When unpacking, the bits are shifted to the right again, and they are bitwise anded together with 15 to filter out any excess bits. This is what that last operation looks like to get b out again:
00000000aaaabbbb //big shifted 4 bits to the right
& 0000000000001111 //anded together with 15
-> 000000000000bbbb //gives the original number b
All is working exactly like in base 10 (or 16). Here after your corrected example.
Three numbers into One number :
7x12^2=1008
5*12^1=60
2*12^0=2
1008+60+2=1070
Now getting back Three numbers from One number :
1070 MOD 12 = 2 (the third number)
1070/12 = 89 (integer division) => 89 MOD 12 = 5
89 / 12 = 7
Note also that the maximum value will be 11*12*12+11*12+11=1727.
If this is really programming related, you will be using 16bits instead of 3*8 bits so sparing one byte. An easyer method not using base 12 would be fit each number into half a byte (better code efficiency and same transmission length):
7<<(4+4) + 5<<4 + 2 = 1874
1874 & 0x000F = 2
1874>>4 & 0x000F = 5
1874>>8 & 0x0F = 7
Because MOD(12) and division by 12 is much less efficient than working with powers of 2
you can use the principle of the positional notation to change from one or the other in any base
Treat yours numbers (n0,n1,...,nm) as a digit of a big number in the base B of your choosing so the new number is
N = n0*B^0 + n1*B^1 + ... + nm*B^m
to revert the process is also simple, while your number is greater than 0 find its modulo in respect to the base to get to get the first digit, then subtracts that digit and divide for the base, repeat until finish while saving each digit along the way
digit_list = []
while N > 0 do:
d = N mod B
N = (N - d) / B
digit_list.append( d )
then if N is N = n0*B^0 + n1*B^1 + ... + nm*B^m doing N mod B give you n0, then subtract it leaving you with n1*B^1 + ... + nm*B^m and divide by B to reduce the exponents of all B and that is the new N, N = n1*B^0 + ... + nm*B^(m-1) repetition of that give you all the digit you start with
here is a working example in python
def compact_num( num_list, base=12 ):
return sum( n*pow(base,i) for i,n in enumerate(num_list) )
def decompact_num( n, base=12):
if n==0:
return [0]
result = []
while n:
n,d = divmod(n,base)
result.append(d)
return result
example
>>> compact_num([2,5,7])
1070
>>> decompact_num(1070)
[2, 5, 7]
>>> compact_num([10,2],16)
42
>>> decompact_num(42,16)
[10, 2]
>>>
This has got to be a well-traveled gotcha of some sort. Define the following function foo():
>>> def foo():
... x = 1
... while x != 0:
... x -= .1
... if x < 0:
... x = 0
... print x
So of course, when we call the function, we get exactly what we expect to get.
>>> foo()
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
1.38777878078e-16 # O_o
0
So, I know that math with integers vs. floating point numbers can get a little weird. Just typing 3 - 2.9 yields such an answer:
>>> 3 - 2.9
0.10000000000000009
So, in fairness -- this is not causing an issue in the script I'm mucking about with. But surely this creeps up and bites people who would actually be affected by values as astronomically small as 1.38777878078e-16. And in order to prevent there from ever being an issue because of the strangely small number, I've got this gem sitting at the bottom of my controller du jour:
if (x < .1 and x > 0) or x < 0:
x = 0
That can't be the solution... unless it totally is. So... is it? If not, what's the trick here?
This can certainly "creep up and bite people", generally when they try to compare floats:
>>> a = 1 / 10
>>> b = 0.6 - 0.5
>>> a == b
False
Therefore it is common to compare floats using a tolerance:
>>> tolerance = 0.000001
>>> abs(a - b) < tolerance
True
This program:
def foo():
x = 1
while x != 0:
x -= .1
if x < 0:
x = 0
print '%.20f' % x
foo()
prints out this:
0.90000000000000002220
0.80000000000000004441
0.70000000000000006661
0.60000000000000008882
0.50000000000000011102
0.40000000000000013323
0.30000000000000015543
0.20000000000000014988
0.10000000000000014433
0.00000000000000013878
0.00000000000000000000
You were not printing the numbers out with enough precision to see what was actually going on. Compare this with the output of print '%.20f' % x when you explicitly set x to 0.9 and 0.8 and so forth. You may want to pay particular attention to the result for 0.5.
You miss the point - that isn't something you want to have a workaround for. Just trust VM, and assume, that it does all the computations as they should be done.
What you want to do, is to format your number. Spot the difference between value, and its representation.
>>> x = 0.9
>>> while x>0.1:
... x -= 0.1
...
>>> x
1.3877787807814457e-16
>>> "{:.2f}".format(x)
'0.00'
Here you have example of showing you value with 2 decimal points. More on formatting (number formatting too) you'll find HERE
I have a mathematical problem that is part of my programming problem
I have a statement like
a = b%30;
How can I calculate b in terms of a?
I gave it a thought but couldn't figure it out.
By definition,
b == 30*n + a
for some integer n.
Note that there are multiple b values that can give you the same a:
>>> b = 31
>>> b % 30
1
>>> b = 61
>>> b % 30
1
First, obviously, there are in general several solutions for b for a given a.
If % is the remainder operator found in most programming languages, then the sign of a is critical. You know that this is a website for programming questions, right?
If |a|>=30, then there are no solutions
If a = 0, the solutions are the multiples of 30.
If 0 < a < 30, the solutions are all the b such that b = 30 * k + a for some positive integer k.
If -30 < a < 0, the solutions are all the b such that b = - (30 * k - a) for some positive integer k.
I know I need to use the extended euclidean algorithm, but I'm not sure exactly what calculations I need to do. I have huge numbers. Thanks
Well, d is chosen such that d * e == 1 modulo (p-1)(q-1), so you could use the Euclidean algorithm for that (finding the modular multiplicative inverse).
If you are not interested in understanding the algorithm, you can just call BigInteger#modInverse directly.
d = e.modInverse(p_1.multiply(q_1))
Given that, p=11, q=7, e =17, n=77, φ (n) = 60 and d=?
First substitute values from the formula:-
ed mod φ (n) =1
17 d mod 60 = 1
The next step: – take the totient of n, which is 60 to your left hand side and [e] to your right hand side.
60 = 17
3rd step: – ask how many times 17 goes to 60. That is 3.5….. Ignore the remainder and take 3.
60 = 3(17)
Step 4: – now you need to balance this equation 60 = 3(17) such that left hand side equals to right hand side. How?
60 = 3(17) + 9 <== if you multiply 3 by 17 you get 51 then plus 9, that is 60. Which means both sides are now equal.
Step 5: – Now take 17 to your left hand side and 9 to your right hand side.
17 = 9
Step 6:- ask how many times 9 goes to 17. That is 1.8…….
17 = 1(9)
Step 7:- Step 4: – now you need to balance this 17 = 1(9)
17 = 1(9) + 8 <== if you multiply 1 by 9 you get 9 then plus 8, that is 17. Which means both sides are now equal.
Step 8:- again take 9 to your left hand side and 8 to your right hand side.
9 = 1(8)
9 = 1(8) + 1 <== once you reached +1 to balance your equation, you may stop and start doing back substitution.
Step A:-Last equation in step 8 which is 9 = 1(8) + 1 can be written as follows:
1.= 9 – 1(8)
Step B:-We know what is (8) by simple saying 8 = 17 – 1(9) from step 7. Now we can re-write step A as:-
1=9 -1(17 – 1(9)) <== here since 9=1(9) we can re-write as:-
1=1(9)-1(17) +1(9) <== group similar terms. In this case you add 1(9) with 1(9) – that is 2(9).
1=2(9)-1(17)
Step C: – We know what is (9) by simple saying 9 = 60 – 3(17) from step 4. Now we can re-write step B as:-
1=2(60-3(17) -1(17)
1=2(60)-6(17) -1(17) <== group similar terms. In this case you add 6(17) with 1(17) – that is 7(17).
1=2(60)-7(17) <== at this stage we can stop, nothing more to substitute, therefore take the value next 17. That is 7. Subtract it with the totient.
60-7=d
Then therefore the value of d= 53.
I just want to augment the Sidudozo's answer and clarify some important points.
First of all, what should we pass to Extended Euclidean Algorthim to compute d ?
Remember that ed mod φ(n) = 1 and cgd(e, φ(n)) = 1.
Knowing that the Extended Euclidean Algorthim is based on the formula cgd(a,b) = as + bt, hence cgd(e, φ(n)) = es + φ(n)t = 1, where d should be equal to s + φ(n) in order to satisfy the
ed mod φ(n) = 1 condition.
So, given the e=17 and φ(n)=60 (borrowed from the Sidudozo's answer), we substitute the corresponding values in the formula mentioned above:
cgd(e, φ(n)) = es + φ(n)t = 1 ⇔ 17s + 60t = 1.
At the end of the Sidudozo's answer we obtain s = -7. Thus d = s + φ(n) ⇔ d = -7 + 60 ⇒ d = 53.
Let's verify the results. The condition was ed mod φ(n) = 1.
Look 17 * 53 mod 60 = 1. Correct!
The approved answer by Thilo is incorrect as it uses Euler's totient function instead of Carmichael's totient function to find d. While the original method of RSA key generation uses Euler's function, d is typically derived using Carmichael's function instead for reasons I won't get into. The math needed to find the private exponent d given p q and e without any fancy notation would be as follows:
d = e^-1*mod(((p-1)/GCD(p-1,q-1))(q-1))
Why is this? Because d is defined in the relationship
de = 1*mod(λ(n))
Where λ(n) is Carmichael's function which is
λ(n)=lcm(p-1,q-1)
Which can be expanded to
λ(n)=((p-1)/GCD(p-1,q-1))(q-1)
So inserting this into the original expression that defines d we get
de = 1*mod(((p-1)/GCD(p-1,q-1))(q-1))
And just rearrange that to the final formula
d = e^-1*mod(((p-1)/GCD(p-1,q-1))(q-1))
More related information can be found here.
Here's the code for it, in python:
def inverse(a, n):
t, newt = 0, 1
r, newr = n, a
while newr:
quotient = r // newr # floor division
t, newt = newt, t - quotient * newt
r, newr = newr, r - quotient * newr
if r > 1:
return None # there's no solution
if t < 0:
t = t + n
return t
inverse(17, 60) # returns 53
adapted from pseudocode found in wiki: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode
Simply use this formula,
d = (1+K(phi))/e. (Very useful when e and phi are small numbers)
Lets say, e = 3 and phi = 40
we assume K = 0, 1, 2... until your d value is not a decimal
assume K = 0, then
d = (1+0(40))/3 = 0. (if it is a decimal increase the K value, don't bother finding the exact value of the decimal)
assume K = 2, then
d = (1+2(40)/3) = 81/3 = 27
d = 27.
Assuming K will become exponentially easy with practice.
Taken the values p=7, q=11 and e=17.
then the value of n=p*q=77 and f(n)=(p-1)(q-1)=60.
Therefore, our public key pair is,(e,n)=(7,77)
Now for calvulating the value of d we have the constraint,
e*d == 1 mod (f(n)), [here "==" represents the **congruent symbol**].
17*d == 1 mod 60
(17*53)*d == 53 mod 60, [7*53=901, which gives modulus value 1]
1*d == 53 mod 60
hence,this gives the value of d=53.
Therefore our private key pair will be, (d,n)=(53,77).
Hope this help. Thank you!