Canola
0.8.D001
|
00001 // 00002 // canola - canon canola 1614p emulator 00003 // Copyright (C) 2011, 2012 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License, version 3, as 00007 // published by the Free Software Foundation. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License along 00015 // with this program. If not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 #include <lib/ac/assert.h> 00019 00020 #include <lib/number.h> 00021 00022 00023 number 00024 number::sqrt(void) 00025 const 00026 { 00027 if (is_zero()) 00028 return number(); 00029 00030 enum { blue_shift = 15 }; 00031 assert(blue_shift < 16); 00032 00033 // 00034 // Instruction Manual, p. 8 00035 // 00036 // "Square Root Key 00037 // 00038 // "Used for finding square roots. When this key is depressed the 00039 // indicated value is square rooted. The result of the square root 00040 // operation is indicated by a positive value regardless of positive or 00041 // negative value. It is not necessary to depress the [+=] key after 00042 // this key has been depressed." 00043 // 00044 number_z a(value.shift_left(2 * blue_shift - decimal)); 00045 00046 // 00047 // We are going to use a Newton-Raphson approximation 00048 // with quadratic convergence. 00049 // 00050 // FIXME: How about Halley's Method, with cubic convergence? 00051 // The 1614P almost certainly did N-R in hardware. 00052 // 00053 number_z epsilon(1000u); 00054 number_z x = number_z::one().shift_left(blue_shift + decimal / 2); 00055 for (;;) 00056 { 00057 number_z x2 = (x + a / x) / 2u; 00058 if ((x2 < x ? x - x2 : x2 - x) < epsilon) 00059 break; 00060 x = x2; 00061 } 00062 00063 // 00064 // Because it is a square root, the number of digits to the left of 00065 // the decimal point always reduces or stays the same. 00066 // This means we will never get an overflow. 00067 // 00068 assert(x < number_z::one().shift_left(16 + blue_shift)); 00069 00070 unsigned x_dec = blue_shift; 00071 truncate_floating_operation(x, x_dec); 00072 00073 // <question> 00074 // Does sqrt strip redundant zero decimal places to the right of the 00075 // decimal point? Does [9] [sqrt] display "3." or "3.0000000000000000"? 00076 // </question> 00077 strip_redundant_decimal_places(x, x_dec); 00078 00079 return number(x, x_dec); 00080 } 00081 00082 00083 // vim: set ts=8 sw=4 et :