Commit | Line | Data |
---|---|---|
770911a3 EH |
1 | /* |
2 | * Copyright 2015 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | */ | |
23 | #include <asm/div64.h> | |
24 | ||
25 | #define SHIFT_AMOUNT 16 /* We multiply all original integers with 2^SHIFT_AMOUNT to get the fInt representation */ | |
26 | ||
27 | #define PRECISION 5 /* Change this value to change the number of decimal places in the final output - 5 is a good default */ | |
28 | ||
29 | #define SHIFTED_2 (2 << SHIFT_AMOUNT) | |
30 | #define MAX (1 << (SHIFT_AMOUNT - 1)) - 1 /* 32767 - Might change in the future */ | |
31 | ||
32 | /* ------------------------------------------------------------------------------- | |
33 | * NEW TYPE - fINT | |
34 | * ------------------------------------------------------------------------------- | |
35 | * A variable of type fInt can be accessed in 3 ways using the dot (.) operator | |
36 | * fInt A; | |
37 | * A.full => The full number as it is. Generally not easy to read | |
38 | * A.partial.real => Only the integer portion | |
39 | * A.partial.decimal => Only the fractional portion | |
40 | */ | |
41 | typedef union _fInt { | |
42 | int full; | |
43 | struct _partial { | |
44 | unsigned int decimal: SHIFT_AMOUNT; /*Needs to always be unsigned*/ | |
45 | int real: 32 - SHIFT_AMOUNT; | |
46 | } partial; | |
47 | } fInt; | |
48 | ||
49 | /* ------------------------------------------------------------------------------- | |
50 | * Function Declarations | |
51 | * ------------------------------------------------------------------------------- | |
52 | */ | |
53 | fInt ConvertToFraction(int); /* Use this to convert an INT to a FINT */ | |
54 | fInt Convert_ULONG_ToFraction(uint32_t); /* Use this to convert an uint32_t to a FINT */ | |
55 | fInt GetScaledFraction(int, int); /* Use this to convert an INT to a FINT after scaling it by a factor */ | |
56 | int ConvertBackToInteger(fInt); /* Convert a FINT back to an INT that is scaled by 1000 (i.e. last 3 digits are the decimal digits) */ | |
57 | ||
58 | fInt fNegate(fInt); /* Returns -1 * input fInt value */ | |
59 | fInt fAdd (fInt, fInt); /* Returns the sum of two fInt numbers */ | |
60 | fInt fSubtract (fInt A, fInt B); /* Returns A-B - Sometimes easier than Adding negative numbers */ | |
61 | fInt fMultiply (fInt, fInt); /* Returns the product of two fInt numbers */ | |
62 | fInt fDivide (fInt A, fInt B); /* Returns A/B */ | |
63 | fInt fGetSquare(fInt); /* Returns the square of a fInt number */ | |
64 | fInt fSqrt(fInt); /* Returns the Square Root of a fInt number */ | |
65 | ||
66 | int uAbs(int); /* Returns the Absolute value of the Int */ | |
67 | fInt fAbs(fInt); /* Returns the Absolute value of the fInt */ | |
68 | int uPow(int base, int exponent); /* Returns base^exponent an INT */ | |
69 | ||
70 | void SolveQuadracticEqn(fInt, fInt, fInt, fInt[]); /* Returns the 2 roots via the array */ | |
71 | bool Equal(fInt, fInt); /* Returns true if two fInts are equal to each other */ | |
72 | bool GreaterThan(fInt A, fInt B); /* Returns true if A > B */ | |
73 | ||
74 | fInt fExponential(fInt exponent); /* Can be used to calculate e^exponent */ | |
75 | fInt fNaturalLog(fInt value); /* Can be used to calculate ln(value) */ | |
76 | ||
77 | /* Fuse decoding functions | |
78 | * ------------------------------------------------------------------------------------- | |
79 | */ | |
80 | fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength); | |
81 | fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength); | |
82 | fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength); | |
83 | ||
84 | /* Internal Support Functions - Use these ONLY for testing or adding to internal functions | |
85 | * ------------------------------------------------------------------------------------- | |
86 | * Some of the following functions take two INTs as their input - This is unsafe for a variety of reasons. | |
87 | */ | |
88 | fInt Add (int, int); /* Add two INTs and return Sum as FINT */ | |
89 | fInt Multiply (int, int); /* Multiply two INTs and return Product as FINT */ | |
90 | fInt Divide (int, int); /* You get the idea... */ | |
91 | fInt fNegate(fInt); | |
92 | ||
93 | int uGetScaledDecimal (fInt); /* Internal function */ | |
94 | int GetReal (fInt A); /* Internal function */ | |
95 | ||
96 | /* Future Additions and Incomplete Functions | |
97 | * ------------------------------------------------------------------------------------- | |
98 | */ | |
99 | int GetRoundedValue(fInt); /* Incomplete function - Useful only when Precision is lacking */ | |
100 | /* Let us say we have 2.126 but can only handle 2 decimal points. We could */ | |
101 | /* either chop of 6 and keep 2.12 or use this function to get 2.13, which is more accurate */ | |
102 | ||
103 | /* ------------------------------------------------------------------------------------- | |
104 | * TROUBLESHOOTING INFORMATION | |
105 | * ------------------------------------------------------------------------------------- | |
106 | * 1) ConvertToFraction - InputOutOfRangeException: Only accepts numbers smaller than MAX (default: 32767) | |
107 | * 2) fAdd - OutputOutOfRangeException: Output bigger than MAX (default: 32767) | |
108 | * 3) fMultiply - OutputOutOfRangeException: | |
109 | * 4) fGetSquare - OutputOutOfRangeException: | |
110 | * 5) fDivide - DivideByZeroException | |
111 | * 6) fSqrt - NegativeSquareRootException: Input cannot be a negative number | |
112 | */ | |
113 | ||
114 | /* ------------------------------------------------------------------------------------- | |
115 | * START OF CODE | |
116 | * ------------------------------------------------------------------------------------- | |
117 | */ | |
118 | fInt fExponential(fInt exponent) /*Can be used to calculate e^exponent*/ | |
119 | { | |
75ac63db RZ |
120 | uint32_t i; |
121 | bool bNegated = false; | |
770911a3 | 122 | |
75ac63db RZ |
123 | fInt fPositiveOne = ConvertToFraction(1); |
124 | fInt fZERO = ConvertToFraction(0); | |
770911a3 | 125 | |
75ac63db RZ |
126 | fInt lower_bound = Divide(78, 10000); |
127 | fInt solution = fPositiveOne; /*Starting off with baseline of 1 */ | |
128 | fInt error_term; | |
770911a3 | 129 | |
75ac63db RZ |
130 | uint32_t k_array[11] = {55452, 27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78}; |
131 | uint32_t expk_array[11] = {2560000, 160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078}; | |
770911a3 | 132 | |
75ac63db RZ |
133 | if (GreaterThan(fZERO, exponent)) { |
134 | exponent = fNegate(exponent); | |
135 | bNegated = true; | |
136 | } | |
770911a3 | 137 | |
75ac63db RZ |
138 | while (GreaterThan(exponent, lower_bound)) { |
139 | for (i = 0; i < 11; i++) { | |
140 | if (GreaterThan(exponent, GetScaledFraction(k_array[i], 10000))) { | |
141 | exponent = fSubtract(exponent, GetScaledFraction(k_array[i], 10000)); | |
142 | solution = fMultiply(solution, GetScaledFraction(expk_array[i], 10000)); | |
143 | } | |
144 | } | |
145 | } | |
770911a3 | 146 | |
75ac63db | 147 | error_term = fAdd(fPositiveOne, exponent); |
770911a3 | 148 | |
75ac63db | 149 | solution = fMultiply(solution, error_term); |
770911a3 | 150 | |
75ac63db RZ |
151 | if (bNegated) |
152 | solution = fDivide(fPositiveOne, solution); | |
770911a3 | 153 | |
75ac63db | 154 | return solution; |
770911a3 EH |
155 | } |
156 | ||
157 | fInt fNaturalLog(fInt value) | |
158 | { | |
75ac63db RZ |
159 | uint32_t i; |
160 | fInt upper_bound = Divide(8, 1000); | |
161 | fInt fNegativeOne = ConvertToFraction(-1); | |
162 | fInt solution = ConvertToFraction(0); /*Starting off with baseline of 0 */ | |
163 | fInt error_term; | |
164 | ||
165 | uint32_t k_array[10] = {160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078}; | |
166 | uint32_t logk_array[10] = {27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78}; | |
167 | ||
168 | while (GreaterThan(fAdd(value, fNegativeOne), upper_bound)) { | |
169 | for (i = 0; i < 10; i++) { | |
170 | if (GreaterThan(value, GetScaledFraction(k_array[i], 10000))) { | |
171 | value = fDivide(value, GetScaledFraction(k_array[i], 10000)); | |
172 | solution = fAdd(solution, GetScaledFraction(logk_array[i], 10000)); | |
173 | } | |
174 | } | |
175 | } | |
176 | ||
177 | error_term = fAdd(fNegativeOne, value); | |
178 | ||
179 | return (fAdd(solution, error_term)); | |
770911a3 EH |
180 | } |
181 | ||
182 | fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength) | |
183 | { | |
75ac63db RZ |
184 | fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value); |
185 | fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1); | |
770911a3 | 186 | |
75ac63db | 187 | fInt f_decoded_value; |
770911a3 | 188 | |
75ac63db RZ |
189 | f_decoded_value = fDivide(f_fuse_value, f_bit_max_value); |
190 | f_decoded_value = fMultiply(f_decoded_value, f_range); | |
191 | f_decoded_value = fAdd(f_decoded_value, f_min); | |
770911a3 | 192 | |
75ac63db | 193 | return f_decoded_value; |
770911a3 EH |
194 | } |
195 | ||
196 | ||
197 | fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength) | |
198 | { | |
75ac63db RZ |
199 | fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value); |
200 | fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1); | |
770911a3 | 201 | |
75ac63db RZ |
202 | fInt f_CONSTANT_NEG13 = ConvertToFraction(-13); |
203 | fInt f_CONSTANT1 = ConvertToFraction(1); | |
770911a3 | 204 | |
75ac63db | 205 | fInt f_decoded_value; |
770911a3 | 206 | |
75ac63db RZ |
207 | f_decoded_value = fSubtract(fDivide(f_bit_max_value, f_fuse_value), f_CONSTANT1); |
208 | f_decoded_value = fNaturalLog(f_decoded_value); | |
209 | f_decoded_value = fMultiply(f_decoded_value, fDivide(f_range, f_CONSTANT_NEG13)); | |
210 | f_decoded_value = fAdd(f_decoded_value, f_average); | |
770911a3 | 211 | |
75ac63db | 212 | return f_decoded_value; |
770911a3 EH |
213 | } |
214 | ||
215 | fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength) | |
216 | { | |
75ac63db RZ |
217 | fInt fLeakage; |
218 | fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1); | |
770911a3 | 219 | |
75ac63db RZ |
220 | fLeakage = fMultiply(ln_max_div_min, Convert_ULONG_ToFraction(leakageID_fuse)); |
221 | fLeakage = fDivide(fLeakage, f_bit_max_value); | |
222 | fLeakage = fExponential(fLeakage); | |
223 | fLeakage = fMultiply(fLeakage, f_min); | |
770911a3 | 224 | |
75ac63db | 225 | return fLeakage; |
770911a3 EH |
226 | } |
227 | ||
228 | fInt ConvertToFraction(int X) /*Add all range checking here. Is it possible to make fInt a private declaration? */ | |
229 | { | |
75ac63db | 230 | fInt temp; |
770911a3 | 231 | |
75ac63db RZ |
232 | if (X <= MAX) |
233 | temp.full = (X << SHIFT_AMOUNT); | |
234 | else | |
235 | temp.full = 0; | |
770911a3 | 236 | |
75ac63db | 237 | return temp; |
770911a3 EH |
238 | } |
239 | ||
240 | fInt fNegate(fInt X) | |
241 | { | |
75ac63db RZ |
242 | fInt CONSTANT_NEGONE = ConvertToFraction(-1); |
243 | return (fMultiply(X, CONSTANT_NEGONE)); | |
770911a3 EH |
244 | } |
245 | ||
246 | fInt Convert_ULONG_ToFraction(uint32_t X) | |
247 | { | |
75ac63db | 248 | fInt temp; |
770911a3 | 249 | |
75ac63db RZ |
250 | if (X <= MAX) |
251 | temp.full = (X << SHIFT_AMOUNT); | |
252 | else | |
253 | temp.full = 0; | |
770911a3 | 254 | |
75ac63db | 255 | return temp; |
770911a3 EH |
256 | } |
257 | ||
258 | fInt GetScaledFraction(int X, int factor) | |
259 | { | |
75ac63db RZ |
260 | int times_shifted, factor_shifted; |
261 | bool bNEGATED; | |
262 | fInt fValue; | |
263 | ||
264 | times_shifted = 0; | |
265 | factor_shifted = 0; | |
266 | bNEGATED = false; | |
267 | ||
268 | if (X < 0) { | |
269 | X = -1*X; | |
270 | bNEGATED = true; | |
271 | } | |
272 | ||
273 | if (factor < 0) { | |
274 | factor = -1*factor; | |
275 | bNEGATED = !bNEGATED; /*If bNEGATED = true due to X < 0, this will cover the case of negative cancelling negative */ | |
276 | } | |
277 | ||
278 | if ((X > MAX) || factor > MAX) { | |
279 | if ((X/factor) <= MAX) { | |
280 | while (X > MAX) { | |
281 | X = X >> 1; | |
282 | times_shifted++; | |
283 | } | |
284 | ||
285 | while (factor > MAX) { | |
286 | factor = factor >> 1; | |
287 | factor_shifted++; | |
288 | } | |
289 | } else { | |
290 | fValue.full = 0; | |
291 | return fValue; | |
292 | } | |
293 | } | |
294 | ||
295 | if (factor == 1) | |
296 | return (ConvertToFraction(X)); | |
297 | ||
298 | fValue = fDivide(ConvertToFraction(X * uPow(-1, bNEGATED)), ConvertToFraction(factor)); | |
299 | ||
300 | fValue.full = fValue.full << times_shifted; | |
301 | fValue.full = fValue.full >> factor_shifted; | |
302 | ||
303 | return fValue; | |
770911a3 EH |
304 | } |
305 | ||
306 | /* Addition using two fInts */ | |
307 | fInt fAdd (fInt X, fInt Y) | |
308 | { | |
75ac63db | 309 | fInt Sum; |
770911a3 | 310 | |
75ac63db | 311 | Sum.full = X.full + Y.full; |
770911a3 | 312 | |
75ac63db | 313 | return Sum; |
770911a3 EH |
314 | } |
315 | ||
316 | /* Addition using two fInts */ | |
317 | fInt fSubtract (fInt X, fInt Y) | |
318 | { | |
75ac63db | 319 | fInt Difference; |
770911a3 | 320 | |
75ac63db | 321 | Difference.full = X.full - Y.full; |
770911a3 | 322 | |
75ac63db | 323 | return Difference; |
770911a3 EH |
324 | } |
325 | ||
326 | bool Equal(fInt A, fInt B) | |
327 | { | |
75ac63db RZ |
328 | if (A.full == B.full) |
329 | return true; | |
330 | else | |
331 | return false; | |
770911a3 EH |
332 | } |
333 | ||
334 | bool GreaterThan(fInt A, fInt B) | |
335 | { | |
75ac63db RZ |
336 | if (A.full > B.full) |
337 | return true; | |
338 | else | |
339 | return false; | |
770911a3 EH |
340 | } |
341 | ||
342 | fInt fMultiply (fInt X, fInt Y) /* Uses 64-bit integers (int64_t) */ | |
343 | { | |
75ac63db RZ |
344 | fInt Product; |
345 | int64_t tempProduct; | |
346 | bool X_LessThanOne, Y_LessThanOne; | |
770911a3 | 347 | |
75ac63db RZ |
348 | X_LessThanOne = (X.partial.real == 0 && X.partial.decimal != 0 && X.full >= 0); |
349 | Y_LessThanOne = (Y.partial.real == 0 && Y.partial.decimal != 0 && Y.full >= 0); | |
770911a3 | 350 | |
75ac63db RZ |
351 | /*The following is for a very specific common case: Non-zero number with ONLY fractional portion*/ |
352 | /* TEMPORARILY DISABLED - CAN BE USED TO IMPROVE PRECISION | |
770911a3 | 353 | |
75ac63db RZ |
354 | if (X_LessThanOne && Y_LessThanOne) { |
355 | Product.full = X.full * Y.full; | |
356 | return Product | |
357 | }*/ | |
770911a3 | 358 | |
75ac63db RZ |
359 | tempProduct = ((int64_t)X.full) * ((int64_t)Y.full); /*Q(16,16)*Q(16,16) = Q(32, 32) - Might become a negative number! */ |
360 | tempProduct = tempProduct >> 16; /*Remove lagging 16 bits - Will lose some precision from decimal; */ | |
361 | Product.full = (int)tempProduct; /*The int64_t will lose the leading 16 bits that were part of the integer portion */ | |
770911a3 | 362 | |
75ac63db | 363 | return Product; |
770911a3 EH |
364 | } |
365 | ||
366 | fInt fDivide (fInt X, fInt Y) | |
367 | { | |
75ac63db RZ |
368 | fInt fZERO, fQuotient; |
369 | int64_t longlongX, longlongY; | |
770911a3 | 370 | |
75ac63db | 371 | fZERO = ConvertToFraction(0); |
770911a3 | 372 | |
75ac63db RZ |
373 | if (Equal(Y, fZERO)) |
374 | return fZERO; | |
770911a3 | 375 | |
75ac63db RZ |
376 | longlongX = (int64_t)X.full; |
377 | longlongY = (int64_t)Y.full; | |
770911a3 | 378 | |
75ac63db | 379 | longlongX = longlongX << 16; /*Q(16,16) -> Q(32,32) */ |
770911a3 | 380 | |
75ac63db | 381 | div64_s64(longlongX, longlongY); /*Q(32,32) divided by Q(16,16) = Q(16,16) Back to original format */ |
770911a3 | 382 | |
75ac63db RZ |
383 | fQuotient.full = (int)longlongX; |
384 | return fQuotient; | |
770911a3 EH |
385 | } |
386 | ||
387 | int ConvertBackToInteger (fInt A) /*THIS is the function that will be used to check with the Golden settings table*/ | |
388 | { | |
75ac63db | 389 | fInt fullNumber, scaledDecimal, scaledReal; |
770911a3 | 390 | |
75ac63db | 391 | scaledReal.full = GetReal(A) * uPow(10, PRECISION-1); /* DOUBLE CHECK THISSSS!!! */ |
770911a3 | 392 | |
75ac63db | 393 | scaledDecimal.full = uGetScaledDecimal(A); |
770911a3 | 394 | |
75ac63db | 395 | fullNumber = fAdd(scaledDecimal,scaledReal); |
770911a3 | 396 | |
75ac63db | 397 | return fullNumber.full; |
770911a3 EH |
398 | } |
399 | ||
400 | fInt fGetSquare(fInt A) | |
401 | { | |
75ac63db | 402 | return fMultiply(A,A); |
770911a3 EH |
403 | } |
404 | ||
405 | /* x_new = x_old - (x_old^2 - C) / (2 * x_old) */ | |
406 | fInt fSqrt(fInt num) | |
407 | { | |
75ac63db RZ |
408 | fInt F_divide_Fprime, Fprime; |
409 | fInt test; | |
410 | fInt twoShifted; | |
411 | int seed, counter, error; | |
412 | fInt x_new, x_old, C, y; | |
770911a3 | 413 | |
75ac63db | 414 | fInt fZERO = ConvertToFraction(0); |
770911a3 | 415 | |
75ac63db | 416 | /* (0 > num) is the same as (num < 0), i.e., num is negative */ |
770911a3 | 417 | |
75ac63db RZ |
418 | if (GreaterThan(fZERO, num) || Equal(fZERO, num)) |
419 | return fZERO; | |
770911a3 | 420 | |
75ac63db | 421 | C = num; |
770911a3 | 422 | |
75ac63db RZ |
423 | if (num.partial.real > 3000) |
424 | seed = 60; | |
425 | else if (num.partial.real > 1000) | |
426 | seed = 30; | |
427 | else if (num.partial.real > 100) | |
428 | seed = 10; | |
429 | else | |
430 | seed = 2; | |
431 | ||
432 | counter = 0; | |
770911a3 | 433 | |
75ac63db RZ |
434 | if (Equal(num, fZERO)) /*Square Root of Zero is zero */ |
435 | return fZERO; | |
770911a3 | 436 | |
75ac63db RZ |
437 | twoShifted = ConvertToFraction(2); |
438 | x_new = ConvertToFraction(seed); | |
770911a3 | 439 | |
75ac63db RZ |
440 | do { |
441 | counter++; | |
770911a3 | 442 | |
75ac63db | 443 | x_old.full = x_new.full; |
770911a3 | 444 | |
75ac63db RZ |
445 | test = fGetSquare(x_old); /*1.75*1.75 is reverting back to 1 when shifted down */ |
446 | y = fSubtract(test, C); /*y = f(x) = x^2 - C; */ | |
770911a3 | 447 | |
75ac63db RZ |
448 | Fprime = fMultiply(twoShifted, x_old); |
449 | F_divide_Fprime = fDivide(y, Fprime); | |
770911a3 | 450 | |
75ac63db | 451 | x_new = fSubtract(x_old, F_divide_Fprime); |
770911a3 | 452 | |
75ac63db | 453 | error = ConvertBackToInteger(x_new) - ConvertBackToInteger(x_old); |
770911a3 | 454 | |
75ac63db RZ |
455 | if (counter > 20) /*20 is already way too many iterations. If we dont have an answer by then, we never will*/ |
456 | return x_new; | |
770911a3 | 457 | |
75ac63db RZ |
458 | } while (uAbs(error) > 0); |
459 | ||
460 | return (x_new); | |
770911a3 EH |
461 | } |
462 | ||
463 | void SolveQuadracticEqn(fInt A, fInt B, fInt C, fInt Roots[]) | |
464 | { | |
75ac63db RZ |
465 | fInt *pRoots = &Roots[0]; |
466 | fInt temp, root_first, root_second; | |
467 | fInt f_CONSTANT10, f_CONSTANT100; | |
770911a3 | 468 | |
75ac63db RZ |
469 | f_CONSTANT100 = ConvertToFraction(100); |
470 | f_CONSTANT10 = ConvertToFraction(10); | |
770911a3 | 471 | |
75ac63db RZ |
472 | while(GreaterThan(A, f_CONSTANT100) || GreaterThan(B, f_CONSTANT100) || GreaterThan(C, f_CONSTANT100)) { |
473 | A = fDivide(A, f_CONSTANT10); | |
474 | B = fDivide(B, f_CONSTANT10); | |
475 | C = fDivide(C, f_CONSTANT10); | |
476 | } | |
770911a3 | 477 | |
75ac63db RZ |
478 | temp = fMultiply(ConvertToFraction(4), A); /* root = 4*A */ |
479 | temp = fMultiply(temp, C); /* root = 4*A*C */ | |
480 | temp = fSubtract(fGetSquare(B), temp); /* root = b^2 - 4AC */ | |
481 | temp = fSqrt(temp); /*root = Sqrt (b^2 - 4AC); */ | |
770911a3 | 482 | |
75ac63db RZ |
483 | root_first = fSubtract(fNegate(B), temp); /* b - Sqrt(b^2 - 4AC) */ |
484 | root_second = fAdd(fNegate(B), temp); /* b + Sqrt(b^2 - 4AC) */ | |
770911a3 | 485 | |
75ac63db RZ |
486 | root_first = fDivide(root_first, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */ |
487 | root_first = fDivide(root_first, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */ | |
770911a3 | 488 | |
75ac63db RZ |
489 | root_second = fDivide(root_second, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */ |
490 | root_second = fDivide(root_second, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */ | |
770911a3 | 491 | |
75ac63db RZ |
492 | *(pRoots + 0) = root_first; |
493 | *(pRoots + 1) = root_second; | |
770911a3 EH |
494 | } |
495 | ||
496 | /* ----------------------------------------------------------------------------- | |
497 | * SUPPORT FUNCTIONS | |
498 | * ----------------------------------------------------------------------------- | |
499 | */ | |
500 | ||
501 | /* Addition using two normal ints - Temporary - Use only for testing purposes?. */ | |
502 | fInt Add (int X, int Y) | |
503 | { | |
75ac63db | 504 | fInt A, B, Sum; |
770911a3 | 505 | |
75ac63db RZ |
506 | A.full = (X << SHIFT_AMOUNT); |
507 | B.full = (Y << SHIFT_AMOUNT); | |
770911a3 | 508 | |
75ac63db | 509 | Sum.full = A.full + B.full; |
770911a3 | 510 | |
75ac63db | 511 | return Sum; |
770911a3 EH |
512 | } |
513 | ||
514 | /* Conversion Functions */ | |
515 | int GetReal (fInt A) | |
516 | { | |
75ac63db | 517 | return (A.full >> SHIFT_AMOUNT); |
770911a3 EH |
518 | } |
519 | ||
520 | /* Temporarily Disabled */ | |
521 | int GetRoundedValue(fInt A) /*For now, round the 3rd decimal place */ | |
522 | { | |
75ac63db RZ |
523 | /* ROUNDING TEMPORARLY DISABLED |
524 | int temp = A.full; | |
525 | int decimal_cutoff, decimal_mask = 0x000001FF; | |
526 | decimal_cutoff = temp & decimal_mask; | |
527 | if (decimal_cutoff > 0x147) { | |
528 | temp += 673; | |
529 | }*/ | |
530 | ||
531 | return ConvertBackToInteger(A)/10000; /*Temporary - in case this was used somewhere else */ | |
770911a3 EH |
532 | } |
533 | ||
534 | fInt Multiply (int X, int Y) | |
535 | { | |
75ac63db | 536 | fInt A, B, Product; |
770911a3 | 537 | |
75ac63db RZ |
538 | A.full = X << SHIFT_AMOUNT; |
539 | B.full = Y << SHIFT_AMOUNT; | |
770911a3 | 540 | |
75ac63db | 541 | Product = fMultiply(A, B); |
770911a3 | 542 | |
75ac63db | 543 | return Product; |
770911a3 | 544 | } |
75ac63db | 545 | |
770911a3 EH |
546 | fInt Divide (int X, int Y) |
547 | { | |
75ac63db | 548 | fInt A, B, Quotient; |
770911a3 | 549 | |
75ac63db RZ |
550 | A.full = X << SHIFT_AMOUNT; |
551 | B.full = Y << SHIFT_AMOUNT; | |
770911a3 | 552 | |
75ac63db | 553 | Quotient = fDivide(A, B); |
770911a3 | 554 | |
75ac63db | 555 | return Quotient; |
770911a3 EH |
556 | } |
557 | ||
558 | int uGetScaledDecimal (fInt A) /*Converts the fractional portion to whole integers - Costly function */ | |
559 | { | |
560 | int dec[PRECISION]; | |
561 | int i, scaledDecimal = 0, tmp = A.partial.decimal; | |
562 | ||
563 | for (i = 0; i < PRECISION; i++) { | |
75ac63db RZ |
564 | dec[i] = tmp / (1 << SHIFT_AMOUNT); |
565 | tmp = tmp - ((1 << SHIFT_AMOUNT)*dec[i]); | |
566 | tmp *= 10; | |
567 | scaledDecimal = scaledDecimal + dec[i]*uPow(10, PRECISION - 1 -i); | |
568 | } | |
770911a3 | 569 | |
75ac63db | 570 | return scaledDecimal; |
770911a3 EH |
571 | } |
572 | ||
573 | int uPow(int base, int power) | |
574 | { | |
575 | if (power == 0) | |
576 | return 1; | |
577 | else | |
578 | return (base)*uPow(base, power - 1); | |
579 | } | |
580 | ||
581 | fInt fAbs(fInt A) | |
582 | { | |
583 | if (A.partial.real < 0) | |
584 | return (fMultiply(A, ConvertToFraction(-1))); | |
585 | else | |
586 | return A; | |
587 | } | |
588 | ||
589 | int uAbs(int X) | |
590 | { | |
591 | if (X < 0) | |
592 | return (X * -1); | |
593 | else | |
594 | return X; | |
595 | } | |
596 | ||
597 | fInt fRoundUpByStepSize(fInt A, fInt fStepSize, bool error_term) | |
598 | { | |
75ac63db | 599 | fInt solution; |
770911a3 | 600 | |
75ac63db RZ |
601 | solution = fDivide(A, fStepSize); |
602 | solution.partial.decimal = 0; /*All fractional digits changes to 0 */ | |
770911a3 | 603 | |
75ac63db RZ |
604 | if (error_term) |
605 | solution.partial.real += 1; /*Error term of 1 added */ | |
770911a3 | 606 | |
75ac63db RZ |
607 | solution = fMultiply(solution, fStepSize); |
608 | solution = fAdd(solution, fStepSize); | |
770911a3 | 609 | |
75ac63db | 610 | return solution; |
770911a3 EH |
611 | } |
612 |