View difference between Paste ID: enNm0nSe and LQZPS08e
SHOW: | | - or go back to the newest paste.
1
import java.util.ArrayList;
2-
 * Experimentations autour de nombre flottants en faisant varier le nombre de
2+
import java.util.List;
3-
 * bits de la mantisse.
3+
4
/**
5
 * Experimentations autour de nombre flottants en faisant varier le nombre de bits de la mantisse.
6
 * 
7
 * @author Samuel DEVULDER Avril 2016
8
 */
9
public class FP extends Number implements Comparable<FP> {
10
	// http://www.quinapalus.com/efunc.html
11-
	byte sign, exp;
11+
12
	private static final long serialVersionUID = 1L;
13
	byte sign;
14-
	static final int BITS = 15;
14+
	int exp;
15
	long mantissa;
16-
	static long ONE_MSK = 1l << BITS;
16+
17
	static final int EXPONENT_BITS = 8;
18
	static final int MANTISSA_BITS = 15;
19
20-
	static FP ONE = new FP(1, 0, 1 << BITS);
20+
	static long ONE_MSK = 1l << MANTISSA_BITS;
21
22-
	static FP TWO = new FP(1, 1, 1 << BITS);
22+
23
	static FP LN2 = new FP(1, -1, (long) (Math.log(2) * ONE_MSK * 2 + .5));
24
	static FP ONE = new FP(1, 0, 1 << MANTISSA_BITS);
25
	static FP SQRT2 = new FP(1, 0, (long) (Math.sqrt(2) * ONE_MSK + .5));
26-
	static FP TEN = new FP(1, 3, 10 << (BITS - 3));
26+
	static FP TWO = new FP(1, 1, 1 << MANTISSA_BITS);
27
	static FP LN10 = new FP(1, 1, (long) (Math.log(10) * ONE_MSK / 2 + .5));
28
	static FP E = new FP(1, 1, (long) (Math.exp(1) * ONE_MSK / 2 + .5));
29
	static FP PI = new FP(1, 1, (long) (Math.PI * ONE_MSK / 2 + .5));
30
	static FP TEN = new FP(1, 3, 10 << (MANTISSA_BITS - 3));
31
	static FP MAX = new FP(1, 127, ONE_MSK * 2 - 1);
32
33
	static FP[] NUMS = { ZERO, LN2, ONE, SQRT2, TWO, LN10, E, PI, TEN, MAX };
34
35
	public static void main(String[] args) {
36
		System.out.println("LN2=" + LN2);
37
		System.out.println("ONE=" + ONE);
38
		System.out.println("SQRT2=" + SQRT2);
39
		System.out.println("TWO=" + TWO);
40
		System.out.println("LN10=" + LN10);
41
		System.out.println("PI=" + PI);
42
		System.out.println("TEN=" + TEN);
43
		System.out.println("MAX=" + MAX);
44
		System.out.println("ONE+SQRT2=" + ONE.add(SQRT2));
45
		System.out.println("ONE-SQRT2=" + ONE.sub(SQRT2));
46
		System.out.println("SQRT2-SQRT2=" + SQRT2.sub(SQRT2));
47-
		System.out.println("ln(2)=" + TWO.ln());
47+
48-
		System.out.println("ln(10)=" + TEN.ln());
48+
49
50-
		System.out.println("log10(2)=" + TWO.log10());
50+
		System.out.println("SQRT2 % 1=" + SQRT2.mod(ONE));
51-
		System.out.println("log10(10)=" + TEN.log10());
51+
		System.out.println("SQRT2*TEN % LN2=" + SQRT2.mul(TEN).mod(LN2));
52
53-
		System.out.println("sqrt(2)=" + TWO.sqrt());
53+
54-
		System.out.println("sqrt(10)=" + TEN.sqrt());
54+
55
		System.out.println("parse2=" + new FP("3.141592653589"));
56-
		System.out.println("exp(-2)=" + TWO.neg().exp());
56+
57-
		System.out.println("exp(-1)=" + ONE.neg().exp());
57+
		for (FP x : NUMS) {
58-
		System.out.println("exp(0)=" + ZERO.exp());
58+
			System.out.println("ln(" + x + ")=" + x.ln());
59-
		System.out.println("exp(1)=" + ONE.exp());
59+
			System.out.println("log10(" + x + ")=" + x.log10());
60-
		System.out.println("exp(2)=" + TWO.exp());
60+
			System.out.println("sqrt(" + x + ")=" + x.sqrt());
61-
		System.out.println("exp(ln2)=" + LN2.exp());
61+
			System.out.println("" + x + "²=" + x.square());
62-
		System.out.println("exp(ln10)=" + LN10.exp());
62+
			System.out.println("exp(" + x.neg() + ")=" + x.neg().exp());
63
			System.out.println("exp(" + x + ")=" + x.exp());
64
			System.out.println("sin(" + x + ")=" + x.sin());
65
			System.out.println("cos(" + x + ")=" + x.cos());
66
			System.out.println("sin²+cos²(" + x + ")=" + x.cos().square().add(x.sin().square()));
67
			System.out.println("atan(" + x + ")=" + x.atan());
68
		}
69
70
		// for (FP x = ONE; true;) {
71
		// System.out.println(x);
72
		// FP y = x.add(x);
73
		// if (x.equals(y))
74
		// break;
75
		// x = y;
76
		// }
77
78
		for (long mant = ONE_MSK; mant < 2 * ONE_MSK; ++mant) {
79
			FP x = new FP(1, 0, mant);
80
			x.exp();
81
		}
82
	}
83
84-
		int man = (int) Math.scalb(sgn < 0 ? -d : d, BITS - exp);
84+
85
		build(sign, exp, mantissa);
86
	}
87
88
	protected int sign() {
89
		return sign;
90-
		this.exp = (byte) exp;
90+
91
92
	protected int exponent() {
93-
			throw new RuntimeException("Bad mantissa "
93+
94-
					+ Long.toHexString(this.mantissa));
94+
95
96
	protected long mantissa() {
97
		return mantissa;
98
	}
99
100
	public FP(double d) {
101
		int sgn = d < 0 ? -1 : d > 0 ? 1 : 0;
102
		int exp = Math.getExponent(d);
103
		long man = (long) Math.scalb(sgn < 0 ? -d : d, MANTISSA_BITS - exp);
104
		build(man == 0 ? 0 : sgn, exp, man);
105
	}
106
107
	protected FP build(int sign, int exp, long mantissa) {
108
		this.sign = (byte) sign;
109
110
		int EXP_MSK = (1 << (EXPONENT_BITS - 1)) - 1;
111
		this.exp = (byte) (exp > EXP_MSK ? EXP_MSK : exp < -EXP_MSK ? -EXP_MSK : exp);
112
		this.mantissa = mantissa & (ONE_MSK * 2 - 1);
113
		if (sign != 0 && (mantissa & ONE_MSK) == 0)
114
			throw new RuntimeException("Bad mantissa " + Long.toHexString(this.mantissa));
115
		return this;
116
	}
117
118
	public FP(String s_) {
119
		int i = 0;
120
		char[] s = s_.toCharArray();
121
122
		// read sign
123
		int sgn = 1;
124
		while (i < s.length && (s[i] == '-' || s[i] == '+')) {
125
			if (s[i++] == '-')
126
				sgn = -sgn;
127
		}
128
129
		// read int part
130
		FP v = ZERO;
131
		while (i < s.length && s[i] >= '0' && s[i] <= '9') {
132
			v = v.mul(TEN).add(s[i++] - '0');
133
		}
134
135
		// read decimal
136
		if (i < s.length && s[i] == '.') {
137
			FP div = ONE;
138
			++i;
139
			while (i < s.length && s[i] >= '0' && s[i] <= '9') {
140
				div = div.div(TEN);
141
				v = v.add(div.mul(s[i++] - '0'));
142
			}
143
		}
144
145
		// read exponent
146
		if (i < s.length && (s[i] == 'e' || s[i] == 'E')) {
147
			++i;
148
149-
	static FP[] pow_tab = { TEN.pow(0), TEN.pow(1), TEN.pow(2), TEN.pow(3),
149+
150-
			TEN.pow(4), TEN.pow(5), TEN.pow(6), TEN.pow(7), TEN.pow(8),
150+
151-
			TEN.pow(9) };
151+
152
					sgn2 = -sgn2;
153
			}
154
155
			FP e = ONE;
156
			while (i < s.length && s[i] >= '0' && s[i] <= '9') {
157
				e = e.pow(10).mul(pow_tab[s[i++] - '0']);
158
			}
159
160
			v = sgn2 < 0 ? v.div(e) : v.mul(e);
161
		}
162
163
		if (sgn < 0)
164
			v = v.neg();
165
166
		build(v.sign(), v.exponent(), v.mantissa());
167
	}
168
169-
		double t = mantissa() * Math.pow(2, exponent() - BITS);
169+
	static FP[] pow_tab = { TEN.pow(0), TEN.pow(1), TEN.pow(2), TEN.pow(3), TEN.pow(4), TEN.pow(5), TEN.pow(6), TEN.pow(7), TEN.pow(8), TEN.pow(9) };
170
171
	@Override
172
	public boolean equals(Object obj) {
173
		return obj instanceof FP && compareTo((FP) obj) == 0;
174
	}
175
176
	@Override
177
	public int hashCode() {
178
		if (sign == 0)
179
			return 0;
180
		return (int) ((sign * 31 + mantissa) * 31 + exp);
181
	}
182
183
	@Override
184
	public double doubleValue() {
185
		if (sign() == 0)
186
			return 0;
187
		double t = mantissa() * Math.pow(2, exponent() - MANTISSA_BITS);
188-
		long val = mantissa() >>> (BITS - exponent());
188+
189
	}
190
191
	@Override
192
	public float floatValue() {
193
		return (float) doubleValue();
194
	}
195
196-
		if (exp > BITS)
196+
197
	public int intValue() {
198-
		long m = (2l << BITS) - ((1l << BITS) >>> exp);
198+
199
	}
200
201
	@Override
202
	public long longValue() {
203
		int sgn = sign();
204
		if (sgn == 0)
205-
		FP x = ONE, y = new FP(1, -BITS, 1 << BITS);
205+
206
		long val = mantissa() >>> (MANTISSA_BITS - exponent());
207
		return sgn < 0 ? -val : val;
208
	}
209
210
	public FP mul2() {
211
		return new FP(sign(), exponent() + 1, mantissa());
212
	}
213
214
	public FP div2() {
215
		return new FP(sign(), exponent() - 1, mantissa());
216
	}
217
218
	public FP floor() {
219
		int exp = exponent();
220
		if (exp < 0)
221
			return ZERO;
222
		if (exp > MANTISSA_BITS)
223
			return this;
224
		long m = /* 2*ONE_MSK */ -(ONE_MSK >>> exp);
225
		return new FP(sign(), exp, mantissa() & m);
226
	}
227
228
	static FP PRECISION;
229
230
	static {
231
		FP x = ONE, y = new FP(1, -MANTISSA_BITS, 1 << MANTISSA_BITS);
232
		while (x.compareTo(y) > 0) {
233
			PRECISION = x;
234
			x = x.div(TEN);
235
		}
236
	}
237
238
	public String toString() {
239
		// return Double.toString(doubleValue());
240
241
		// http://stackoverflow.com/questions/2302969/how-to-implement-char-ftoafloat-num-without-sprintf-library-function-i
242
		if (sign() == 0)
243
			return "0";
244
		StringBuilder sb = new StringBuilder();
245
246
		boolean neg = sign() < 0;
247
		FP x = this.abs();
248
		// if(x.mantissa!=0xFFFF) ++x.mantissa;
249
		int m = 0, m1 = 0;
250
		// while(TEN.pow(m+1).compareTo(x)<=0) ++m;
251
		m = x.log10().intValue();
252
		boolean useExp = (m >= 5 || (neg && m >= 3) || m <= -5);
253
		if (neg)
254
			sb.append('-');
255
		// set up for scientific notation
256
		if (useExp) {
257
			if (m < 0)
258
				--m;
259
			x = x.mul(TEN.pow(-m));
260
			m1 = m;
261
			m = 0;
262
		}
263
		if (m < 1.0) {
264
			m = 0;
265
		}
266
		// convert the number
267
		while (x.compareTo(PRECISION) > 0 || m >= 0) {
268
			FP weight = TEN.pow(m);
269
			if (weight.tst() > 0) {
270
				int digit = x.div(weight).intValue();
271
				x = x.sub(weight.mul(digit));
272
				sb.append((char) ('0' + digit));
273
			}
274
			if (m == 0 && x.tst() > 0)
275
				sb.append('.');
276
			m--;
277
		}
278
		if (useExp) {
279-
		return new FP((other.sign() & sign()) == 0 ? 0
279+
280-
				: ((other.sign() ^ sign()) | 1), exponent(), mantissa());
280+
281
			if (m1 > 0) {
282
				sb.append('+');
283
			} else {
284
				sb.append('-');
285
				m1 = -m1;
286
			}
287
			if (m1 > 10) {
288
				sb.append((char) ('0' + m1 / 10));
289
				m1 = m1 % 10;
290
			}
291
			sb.append((char) ('0' + m1));
292
		}
293
		return sb.toString();
294
	};
295
296
	public FP neg() {
297
		return new FP(-sign(), exponent(), mantissa());
298
	}
299
300
	public FP abs() {
301
		return new FP(sign() == 0 ? 0 : 1, exponent(), mantissa());
302
	}
303
304
	public FP mulSign(FP other) {
305
		return new FP((other.sign() & sign()) == 0 ? 0 : ((other.sign() ^ sign()) | 1), exponent(), mantissa());
306-
		long mant = (this.mantissa() * other.mantissa()) >>> BITS;
306+
307-
		if ((mant & (2l << BITS)) != 0) {
307+
308
	public int tst() {
309
		return sign();
310
	}
311
312
	public int compareTo(FP other) {
313
		int d = this.sign() - other.sign();
314
		if (d != 0) {
315
			return d;
316
		}
317
		if (this.sign() == 0)
318
			return 0;
319
		d = this.exponent() - other.exponent();
320
		if (d != 0)
321
			return d;
322
		d = (int) (this.mantissa() - other.mantissa());
323
		return d;
324
	}
325
326
	public FP mul(FP other) {
327
		if ((this.sign() & other.sign()) == 0)
328
			return ZERO;
329
		int sign = (this.sign() ^ other.sign()) | 1;
330
		int exp = this.exponent() + other.exponent();
331
		long mant = (this.mantissa() * other.mantissa()) >>> MANTISSA_BITS;
332
		if ((mant & (2l << MANTISSA_BITS)) != 0) {
333
			mant >>>= 1;
334
			++exp;
335
		}
336
		return new FP(mant == 0 ? 0 : sign, exp, mant);
337
	}
338
339
	public FP mul(double v) {
340
		return mul(new FP(v));
341
	}
342
343
	public FP square() {
344-
		long mant = (this.mantissa() << (1 + BITS)) / other.mantissa();
344+
345-
		if ((mant & (2l << BITS)) != 0) {
345+
346
347
	public FP pow(int n) {
348
		boolean neg = n < 0;
349
		if (neg)
350
			n = -n;
351
		FP x = this, y = ONE;
352
		while (n != 0) {
353
			if ((n & 1) != 0) {
354
				y = y.mul(x);
355
			}
356
			x = x.square();
357
			n >>>= 1;
358
		}
359
		return neg ? y.inv() : y;
360
	}
361
362
	public FP div(FP other) {
363
		if (other.sign() == 0)
364
			return MAX.mulSign(this).mulSign(other);
365
		if (this.sign() == 0)
366
			return ZERO;
367
		int sign = (this.sign() ^ other.sign()) | 1;
368
		int exp = this.exponent() - other.exponent();
369
		long mant = (this.mantissa() << (1 + MANTISSA_BITS)) / other.mantissa();
370
		if ((mant & (2l << MANTISSA_BITS)) != 0) {
371
			mant >>>= 1;
372
		} else {
373
			--exp;
374
		}
375
		return new FP(sign, exp, mant);
376
	}
377
378
	public FP mod(FP other) {
379
		return sub(div(other).floor().mul(other));
380
	}
381
382
	public FP inv() {
383-
			if ((mant & (2l << BITS)) != 0) {
383+
384
	}
385
386
	public FP sub(FP other) {
387
		return add(other.neg());
388
	}
389
390
	public FP add(FP other) {
391-
			while ((mant & (1l << BITS)) == 0) {
391+
392
			return other;
393
		if (other.sign() == 0)
394
			return this;
395
396
		FP small = this;
397
		FP big = other;
398
		if (small.exponent() == big.exponent()) {
399
			if (small.mantissa() > big.mantissa()) {
400
				small = other;
401
				big = this;
402
			}
403-
	static protected FP[] ln = { new FP(8.690628917915396e-06),
403+
404-
			new FP(0.9992996219306662), new FP(-0.4907434587925273),
404+
405-
			new FP(0.2867076984634543), new FP(-0.1332213692732176),
405+
406
		}
407
		int exp = big.exponent();
408
		long mant = big.mantissa();
409
		long delta = small.mantissa() >>> (big.exponent() - small.exponent());
410
		if (big.sign() == small.sign()) {
411-
		FP x = new FP(1, 0, mantissa()).sub(ONE), y = ZERO;
411+
412-
		for (int i = ln.length; --i >= 0;)
412+
			if ((mant & (2l << MANTISSA_BITS)) != 0) {
413-
			y = y.mul(x).add(ln[i]);
413+
414
				++exp;
415
			}
416
		} else {
417
			mant -= delta;
418
			if (mant == 0)
419
				return ZERO;
420
			while ((mant & (1l << MANTISSA_BITS)) == 0) {
421
				mant <<= 1;
422
				--exp;
423
			}
424
		}
425
		return new FP(big.sign(), exp, mant);
426
	}
427
428
	protected FP add(double v) {
429
		return add(new FP(v));
430
	}
431
432-
		long op = mantissa() << BITS;
432+
	static protected FP[] ln = { new FP(8.690628917915396e-06), new FP(0.9992996219306662), new FP(-0.4907434587925273), new FP(0.2867076984634543), new FP(-0.1332213692732176),
433-
		long one = 1l << (BITS + BITS);
433+
434
435
	public FP ln() {
436
		if (sign() <= 0)
437
			return MAX.neg();
438
439
		FP y = ZERO;
440
		if (false) {
441
			// table accurate up to 15 bits
442
			FP x = new FP(1, 0, mantissa()).sub(ONE);
443
			for (int i = ln.length; --i >= 0;)
444
				y = y.mul(x).add(ln[i]);
445
		} else {
446
			// exact algorithm log( [1..2[ )
447
			// multiply mantissa without geting out of the [1..2[
448
			// interval
449
			long x = mantissa(), z = exp_tab[0];
450
			for (int k = 1; k < exp_tab.length; ++k) {
451
				long t = x + (x >> k);
452
				if ((t & 2 * ONE_MSK) == 0) {
453
					x = t;
454
					z -= exp_tab[k];
455
				}
456
			}
457
			int exp = 0;
458
			if (z != 0)
459
				while (z < ONE_MSK) {
460
					z <<= 1;
461
					--exp;
462
				}
463
			y = new FP(z == 0 ? 0 : 1, exp, z);
464
		}
465
		int exp = this.exponent() < 0 ? -this.exponent() : this.exponent();
466
		while (exp > 0) {
467
			y = y.add(LN2);
468
			--exp;
469
		}
470
		if (this.exponent() < 0)
471
			y = y.neg();
472
		return y;
473
	}
474
475-
			long z = mantissa(), y = ONE_MSK, t, k;
475+
476
		return ln().div(LN10);
477-
			for (k = 1; (t = (long) (Math.log((k + 1.0) / k) * ONE_MSK + 0.5)) != 0; k <<= 1) {
477+
478-
				t = z - t;
478+
479
	public FP sqrt() {
480
		if (sign() <= 0)
481-
					y += y / k;
481+
482
483
		long op = mantissa() << MANTISSA_BITS;
484
		long one = 1l << (MANTISSA_BITS + MANTISSA_BITS);
485
		long res = 0;
486
		while (one != 0) {
487
			if (op >= res + one) {
488
				op -= res + one;
489
				res += one << 1;
490
			}
491
			res >>>= 1;
492
			one >>>= 2;
493
		}
494
		/* Do arithmetic rounding to nearest integer */
495
		if (op > res) {
496
			res++;
497
		}
498
499
		FP x = new FP(1, this.exponent() >> 1, res);
500
		if ((this.exponent() & 1) != 0)
501
			x = x.mul(SQRT2);
502
		return x;
503
	}
504
505
	static long[] exp_tab;
506
507
	static {
508
		List<Long> array = new ArrayList<Long>();
509
		for (long k = 1, t = 0; (t = (long) (Math.log((k + 1.0) / k) * ONE_MSK + 0.5)) != 0; k <<= 1)
510
			array.add(t);
511
		exp_tab = new long[array.size()];
512
		for (int i = exp_tab.length; --i >= 0;)
513
			exp_tab[i] = array.get(i).longValue();
514
	}
515
516
	public FP exp() {
517
		// exp(2^x * y) = exp(y)^(2^x) = exp(2^0) * exp(2^-1)
518
519
		if (sign() == 0)
520
			return ONE;
521
522
		// exp(y)
523
		FP x = ONE;
524
		if (false) {
525
			FP y = E;
526
			long m = mantissa(), msk = ONE_MSK;
527
			while (m != 0 && !ONE.equals(y)) {
528
				if ((m & msk) != 0) {
529
					x = x.mul(y);
530
					m ^= msk;
531
				}
532
				y = y.sqrt();
533
				msk >>>= 1;
534
			}
535
		} else {
536
			// optim
537
			long z = mantissa(), y = ONE_MSK;
538
			int exp = 0;
539
			for (int k = 0; k < exp_tab.length; ++k) {
540
				long t = z - exp_tab[k];
541
				if (t >= 0) {
542
					z = t;
543
					y += y >> k;
544
					if ((y & (ONE_MSK * 2)) != 0) {
545
						y >>>= 1;
546
						++exp;
547
					}
548
				}
549
			}
550
			x = new FP(1, exp, y);
551
		}
552
553
		// exp(2^exponent)
554
		int exp = exponent();
555
		while (exp > 0 && !MAX.equals(x)) {
556
			x = x.square();
557
			--exp;
558
		}
559
		while (exp < 0 && !ONE.equals(x)) {
560
			x = x.sqrt();
561
			++exp;
562
		}
563
564
		return sign() < 0 ? x.inv() : x;
565
	}
566
567
	static protected FP[] sin = { new FP(7.068518675814434e-06), new FP(0.9996898644339388), new FP(0.002193716170952744), new FP(-0.1722388650880223),
568
			new FP(0.006097383673278212), new FP(0.005721724054854694) };
569
570
	public FP sin() {
571
		boolean neg = sign() < 0;
572
		FP x = abs().mod(PI.mul2());
573
		if (x.compareTo(PI) >= 0) {
574
			x = x.sub(PI.mul2());
575
			if (x.sign() < 0) {
576
				neg = !neg;
577
				x = x.neg();
578
			}
579
		}
580
		if (x.compareTo(PI.div2()) >= 0) {
581
			x = PI.sub(x);
582
		}
583
		FP y = ZERO;
584
		// table accurate up to 15 bits
585
		for (int i = sin.length; --i >= 0;)
586
			y = y.mul(x).add(sin[i]);
587
		if (neg)
588
			y = y.neg();
589
		return y;
590
	}
591
592
	static protected FP[] cos = { new FP(1.000007068162554), new FP(-0.0003343311503654495), new FP(-0.4974330510416236), new FP(-0.007249836999713618),
593
			new FP(0.05103555758070047), new FP(-0.005721683674851457) };
594
595
	public FP cos() {
596
		// return add(PI.div2()).sin();
597
		boolean neg = false;
598
		FP x = abs().mod(PI.mul2());
599
		if (x.compareTo(PI) >= 0) {
600
			x = PI.mul2().sub(x);
601
		}
602
		if (x.compareTo(PI.div2()) >= 0) {
603
			x = PI.sub(x);
604
			neg = true;
605
		}
606
		FP y = ZERO;
607
		// table accurate up to 15 bits
608
		for (int i = cos.length; --i >= 0;)
609
			y = y.mul(x).add(cos[i]);
610
		if (neg)
611
			y = y.neg();
612
		return y;
613
	}
614
615
	public FP tan() {
616
		return sin().div(cos());
617
	}
618
619
	public FP atan() {
620
		return atan2(ONE);
621
	}
622
623
	static protected FP[] atan = { new FP(-0.0464964749), new FP(0.15931422), new FP(-0.327622764) };
624
625
	public FP atan2(FP x) {
626
		// http://math.stackexchange.com/questions/1098487/atan2-faster-approximation
627
		FP y = this;
628
		FP a = x.abs(), b = y.abs();
629
		if (a.compareTo(b) > 0) {
630
			a = b;
631
			b = x.abs();
632
		}
633
		FP s = a.square();
634
		FP r = atan[0].mul(s).add(atan[1]).mul(s).add(atan[2]).mul(s).mul(a).add(a);
635
		if (y.abs().compareTo(x.abs()) > 0)
636
			r = PI.div2().sub(r);
637
		if (x.sign() < 0)
638
			r = PI.sub(r);
639
		if (y.sign() < 0)
640
			r = r.neg();
641
		return r;
642
	}
643
644
}