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 #include <lib/ac/math.h> 00020 00021 #include <lib/number.h> 00022 00023 00024 number 00025 number::round_up(int preferred_decimal) 00026 const 00027 { 00028 if (has_overflowed()) 00029 return *this; 00030 00031 // Strictly speaking, this rounds away from zero; it does not round 00032 // towards positive infinity, like ANSI C ceil(3) does. 00033 assert(preferred_decimal >= 0); 00034 assert(preferred_decimal < 16); 00035 if (decimal == (unsigned)preferred_decimal) 00036 return *this; 00037 00038 if (decimal < (unsigned)preferred_decimal) 00039 { 00040 size_t more = preferred_decimal - decimal; 00041 return number(value.shift_left(more), preferred_decimal, negative); 00042 } 00043 00044 number_z n(value); 00045 size_t dump = decimal - preferred_decimal; 00046 assert(dump > 0); 00047 00048 // <question> 00049 // When rounding UP to zero decimals, does 2.01 become 2 or 3? This 00050 // is a question of does it only consult the first decimal, or all 00051 // the decimals to be round up? (One is fast, the other is accurate.) 00052 // </question> 00053 #if 1 00054 bool nudge = (n % (number_z::one().shift_left(dump))).is_not_zero(); 00055 #else 00056 bool nudge = (n.get(dump - 1) != 0); 00057 #endif 00058 00059 n = n.shift_right(dump); 00060 if (nudge) 00061 n += number_z::one(); 00062 00063 return number(n, preferred_decimal, negative); 00064 } 00065 00066 00067 number 00068 number::round_off(int preferred_decimal) 00069 const 00070 { 00071 if (has_overflowed()) 00072 return *this; 00073 00074 assert(preferred_decimal >= 0); 00075 assert(preferred_decimal < 16); 00076 if (decimal == (unsigned)preferred_decimal) 00077 return *this; 00078 00079 if (decimal < (unsigned)preferred_decimal) 00080 { 00081 size_t more = preferred_decimal - decimal; 00082 return number(value.shift_left(more), preferred_decimal, negative); 00083 } 00084 00085 number_z n(value); 00086 size_t dump = decimal - preferred_decimal; 00087 assert(dump > 0); 00088 00089 bool nudge = (n.get(dump - 1) >= 5); 00090 00091 n = n.shift_right(dump); 00092 if (nudge) 00093 n += number_z::one(); 00094 00095 return number(n, preferred_decimal, negative); 00096 } 00097 00098 00099 number 00100 number::round_down(int preferred_decimal) 00101 const 00102 { 00103 if (has_overflowed()) 00104 return *this; 00105 00106 // Strictly speaking, this rounds towards zero; it does not round 00107 // towards negative infinity, like ANSI C floor(3) does. 00108 assert(preferred_decimal >= 0); 00109 assert(preferred_decimal < 16); 00110 if (decimal == (unsigned)preferred_decimal) 00111 return *this; 00112 00113 if (decimal < (unsigned)preferred_decimal) 00114 { 00115 size_t more = preferred_decimal - decimal; 00116 return number(value.shift_left(more), preferred_decimal, negative); 00117 } 00118 00119 size_t dump = decimal - preferred_decimal; 00120 assert(dump > 0); 00121 00122 return number(value.shift_right(dump), preferred_decimal, negative); 00123 } 00124 00125 00126 // vim: set ts=8 sw=4 et :