1782 "Created: / 13-06-2017 / 01:27:58 / cg" |
1829 "Created: / 13-06-2017 / 01:27:58 / cg" |
1783 ! ! |
1830 ! ! |
1784 |
1831 |
1785 !QDouble methodsFor:'printing & storing'! |
1832 !QDouble methodsFor:'printing & storing'! |
1786 |
1833 |
1787 printDigitsOn:outStream precision:precision exponentInto:expn |
1834 digitsWithPrecision:precision |
1788 |numDigits r e i d| |
1835 "generate the digits and exponent" |
|
1836 |
|
1837 |numDigits r exp i d out str| |
1789 |
1838 |
1790 numDigits := precision+1. "/ number of digits |
1839 numDigits := precision+1. "/ number of digits |
1791 r := self abs. |
1840 r := self abs. |
1792 self d0 = 0.0 ifTrue:[ |
1841 self d0 = 0.0 ifTrue:[ |
1793 expn value:0. |
1842 ^ { String new:precision withAll:$0 . 0 } |
1794 precision timesRepeat:[ outStream nextPut:$0 ]. |
1843 ]. |
|
1844 |
|
1845 out := WriteStream on:(String new:precision+5). |
|
1846 |
|
1847 "/ determine approx. exponent |
|
1848 exp := self d0 abs log10 floor. |
|
1849 exp < -300 ifTrue:[ |
|
1850 r := r * (10.0 raisedToInteger:300). |
|
1851 r := r / (10.0 raisedToInteger:(exp+300)). |
|
1852 ] ifFalse:[ |
|
1853 exp > 300 ifTrue:[ |
|
1854 self halt. |
|
1855 "/ r := ldexpr(r, -53); |
|
1856 "/ r := r / qd_real(10.0) ^ exp; |
|
1857 "/ r := ldexp(r, 53); |
|
1858 ] ifFalse:[ |
|
1859 r := r / (10.0 asQDouble raisedTo:exp). |
|
1860 ] |
|
1861 ]. |
|
1862 |
|
1863 "/ Fix exponent if we are off by one |
|
1864 (r >= 10.0) ifTrue:[ |
|
1865 r := r / 10.0. |
|
1866 exp := exp + 1. |
|
1867 ] ifFalse:[ |
|
1868 (r < 1.0) ifTrue:[ |
|
1869 r := r * 10.0. |
|
1870 exp := exp - 1. |
|
1871 ] |
|
1872 ]. |
|
1873 |
|
1874 ((r >= 10.0) or:[ r < 1.0 ]) ifTrue:[ |
|
1875 self error:'can''t compute exponent.'. |
|
1876 ]. |
|
1877 |
|
1878 "/ Extract the digits |
|
1879 1 to:numDigits do:[:i | |
|
1880 d := r d0 truncated. |
|
1881 r := r - d. |
|
1882 r := r * 10.0. |
|
1883 |
|
1884 out nextPut:($0 + d). |
|
1885 ]. |
|
1886 |
|
1887 str := out contents. |
|
1888 |
|
1889 "/ Fix out-of-range digits. |
|
1890 "/ huh? what is this???? |
|
1891 "/ how can an "out-of-range" digit appear??? |
|
1892 numDigits to:2 by:-1 do:[:i | |
|
1893 (str at:i) < $0 ifTrue:[ |
|
1894 self halt. |
|
1895 str at:i-1 put:(str at:i-1) - 1. |
|
1896 str at:i put:(str at:i) + 10. |
|
1897 ] ifFalse:[ |
|
1898 (str at:i) > $9 ifTrue:[ |
|
1899 self halt. |
|
1900 str at:i-1 put:(str at:i-1) + 1. |
|
1901 str at:i put:(str at:i) - 10. |
|
1902 ]. |
|
1903 ]. |
|
1904 ]. |
|
1905 |
|
1906 str first <= $0 ifTrue:[ |
|
1907 self error:'non-positive leading digit' |
|
1908 ]. |
|
1909 |
|
1910 "/ Round, handle carry |
|
1911 (str at:numDigits) >= $5 ifTrue:[ |
|
1912 str at:numDigits-1 put:(str at:numDigits-1) + 1. |
|
1913 i := numDigits-1. |
|
1914 [i > 1 and:[(str at:i) > $9]] whileTrue:[ |
|
1915 str at:i put:(str at:i) - 10. |
|
1916 i := i - 1. |
|
1917 str at:i put:(str at:i) + 1. |
|
1918 ] |
|
1919 ]. |
|
1920 |
|
1921 "/ If first digit is 10, shift everything. |
|
1922 str first > $9 ifTrue:[ |
|
1923 exp := exp + 1. |
|
1924 str at:1 put:$0. |
|
1925 str := '1',str |
|
1926 ]. |
|
1927 ^ { (str copyTo:precision) . exp } |
|
1928 |
|
1929 " |
|
1930 1.2345 asQDouble digitsWithPrecision:5 -> #('12345' 0) |
|
1931 12.345 asQDouble digitsWithPrecision:5 -> #('12345' 1) |
|
1932 12345 asQDouble digitsWithPrecision:5 -> #('12345' 4) |
|
1933 12345.1 asQDouble digitsWithPrecision:5 -> #('12345' 4) |
|
1934 12345.9 asQDouble digitsWithPrecision:5 -> #('12346' 4) |
|
1935 |
|
1936 1.2345 asQDouble / 10.0 asQDouble |
|
1937 1.2345 asQDouble / 10.0 |
|
1938 " |
|
1939 |
|
1940 "Created: / 15-06-2017 / 09:10:01 / cg" |
|
1941 ! |
|
1942 |
|
1943 digitsWithPrecision:precision exponentInto:expnHolder |
|
1944 "generate the digits and return exponent info" |
|
1945 |
|
1946 |numDigits r exp i d out str| |
|
1947 |
|
1948 numDigits := precision+1. "/ number of digits |
|
1949 r := self abs. |
|
1950 self d0 = 0.0 ifTrue:[ |
|
1951 expnHolder value:0. |
|
1952 ^ String new:precision withAll:$0 |
|
1953 ]. |
|
1954 |
|
1955 out := WriteStream on:(String new:precision+5). |
|
1956 |
|
1957 "/ determine approx. exponent |
|
1958 exp := self d0 abs log10 floor. |
|
1959 exp < -300 ifTrue:[ |
|
1960 r := r * (10.0 raisedToInteger:300). |
|
1961 r := r / (10.0 raisedToInteger:(exp+300)). |
|
1962 ] ifFalse:[ |
|
1963 exp > 300 ifTrue:[ |
|
1964 self halt. |
|
1965 "/ r := ldexpr(r, -53); |
|
1966 "/ r := r / qd_real(10.0) ^ exp; |
|
1967 "/ r := ldexp(r, 53); |
|
1968 ] ifFalse:[ |
|
1969 r := r / (10.0 asQDouble raisedTo:exp). |
|
1970 ] |
|
1971 ]. |
|
1972 |
|
1973 "/ Fix exponent if we are off by one |
|
1974 (r >= 10.0) ifTrue:[ |
|
1975 r := r / 10.0. |
|
1976 exp := exp + 1. |
|
1977 ] ifFalse:[ |
|
1978 (r < 1.0) ifTrue:[ |
|
1979 r := r * 10.0. |
|
1980 exp := exp - 1. |
|
1981 ] |
|
1982 ]. |
|
1983 |
|
1984 ((r >= 10.0) or:[ r < 1.0 ]) ifTrue:[ |
|
1985 self error:'can''t compute exponent.'. |
|
1986 ]. |
|
1987 |
|
1988 "/ Extract the digits |
|
1989 1 to:numDigits do:[:i | |
|
1990 d := r d0 truncated. |
|
1991 r := r - d. |
|
1992 r := r * 10.0. |
|
1993 |
|
1994 out nextPut:($0 + d). |
|
1995 ]. |
|
1996 |
|
1997 str := out contents. |
|
1998 |
|
1999 "/ Fix out-of-range digits. |
|
2000 "/ huh? what is this???? |
|
2001 "/ how can an "out-of-range" digit appear??? |
|
2002 i := numDigits. |
|
2003 [i > 1] whileTrue:[ |
|
2004 (str at:i) < $0 ifTrue:[ |
|
2005 self halt. |
|
2006 str at:i-1 put:(str at:i-1) - 1. |
|
2007 str at:i put:(str at:i) + 10. |
|
2008 ] ifFalse:[ |
|
2009 (str at:i) > $9 ifTrue:[ |
|
2010 self halt. |
|
2011 str at:i-1 put:(str at:i-1) + 1. |
|
2012 str at:i put:(str at:i) - 10. |
|
2013 ]. |
|
2014 ]. |
|
2015 i := i - 1. |
|
2016 ]. |
|
2017 |
|
2018 (str at:1) <= $0 ifTrue:[ |
|
2019 self error:'non-positive leading digit' |
|
2020 ]. |
|
2021 |
|
2022 "/ Round, handle carry |
|
2023 (str at:numDigits) >= $5 ifTrue:[ |
|
2024 str at:numDigits-1 put:(str at:numDigits-1) + 1. |
|
2025 i := numDigits-1. |
|
2026 [i > 1 and:[(str at:i) > $9]] whileTrue:[ |
|
2027 str at:i put:(str at:i) - 10. |
|
2028 i := i - 1. |
|
2029 str at:i put:(str at:i) + 1. |
|
2030 ] |
|
2031 ]. |
|
2032 |
|
2033 "/ If first digit is 10, shift everything. |
|
2034 (str at:1) > $9 ifTrue:[ |
|
2035 exp := exp + 1. |
|
2036 str at:1 put:$0. |
|
2037 str := '1',str |
|
2038 ]. |
|
2039 expnHolder value:exp. |
|
2040 ^ (str copyTo:precision). |
|
2041 |
|
2042 " |
|
2043 1.2345 asQDouble digitsWithPrecision:5 exponentInto:[:e | Transcript showCR:e] -> '12345' / 0 |
|
2044 12.345 asQDouble digitsWithPrecision:5 exponentInto:[:e | Transcript showCR:e] -> '12345' / 1 |
|
2045 12345 asQDouble digitsWithPrecision:5 exponentInto:[:e | Transcript showCR:e] |
|
2046 12345.1 asQDouble digitsWithPrecision:5 exponentInto:[:e | Transcript showCR:e] |
|
2047 12345.9 asQDouble digitsWithPrecision:5 exponentInto:[:e | Transcript showCR:e] |
|
2048 |
|
2049 1.2345 asQDouble / 10.0 asQDouble |
|
2050 1.2345 asQDouble / 10.0 |
|
2051 " |
|
2052 |
|
2053 "Created: / 15-06-2017 / 09:05:42 / cg" |
|
2054 ! |
|
2055 |
|
2056 printOn:aStream |
|
2057 "return a printed representation of the receiver" |
|
2058 |
|
2059 self d1 = 0.0 ifTrue:[ |
|
2060 self d0 printOn:aStream. |
1795 ^ self. |
2061 ^ self. |
1796 ]. |
2062 ]. |
1797 |
2063 self |
1798 "/ determine approx. exponent |
2064 printOn:aStream precision:0 width:0 |
1799 e := self d0 abs log10 floor. |
2065 fixed:false showPositive:false uppercase:false fillChar:(Character space) |
1800 self halt. |
2066 |
1801 e < -300 ifTrue:[ |
2067 " |
1802 r := r * (10.0 raisedToInteger:300). |
2068 (QDouble fromFloat:1.2345) printOn:Transcript |
1803 r := r / (10.0 raisedToInteger:(e+300)). |
2069 ((QDouble fromFloat:1.2345) / 10.0) printOn:Transcript |
|
2070 " |
|
2071 |
|
2072 "Created: / 15-06-2017 / 01:51:36 / cg" |
|
2073 "Modified (comment): / 15-06-2017 / 08:50:25 / cg" |
|
2074 ! |
|
2075 |
|
2076 printOn:aStream precision:precision width:width |
|
2077 fixed:fixed showPositive:showPositive uppercase:uppercase fillChar:fillChar |
|
2078 |
|
2079 "return a printed representation of the receiver. |
|
2080 This is a parametrized entry, which can be used by printf-like functions" |
|
2081 |
|
2082 |sgn count delta exp| |
|
2083 |
|
2084 self d1 = 0.0 ifTrue:[ |
|
2085 self d0 printOn:aStream. |
|
2086 ^ self. |
|
2087 ]. |
|
2088 |
|
2089 count := 0. |
|
2090 sgn := true. |
|
2091 exp := 0. |
|
2092 |
|
2093 self isInfinite ifTrue:[ |
|
2094 self < 0 ifTrue:[ |
|
2095 aStream nextPut:$-. |
|
2096 count := 1. |
|
2097 ] ifFalse:[ |
|
2098 showPositive ifTrue:[ |
|
2099 aStream nextPut:$+. |
|
2100 count := 1. |
|
2101 ] ifFalse:[ |
|
2102 sgn := false. |
|
2103 ]. |
|
2104 ]. |
|
2105 uppercase ifTrue:[ |
|
2106 aStream nextPutAll:'INF' |
|
2107 ] ifFalse:[ |
|
2108 aStream nextPutAll:'inf' |
|
2109 ]. |
|
2110 count := count + 3. |
1804 ] ifFalse:[ |
2111 ] ifFalse:[ |
1805 e > 300 ifTrue:[ |
2112 self isNaN ifTrue:[ |
1806 ] ifFalse:[ |
2113 uppercase ifTrue:[ |
|
2114 aStream nextPutAll:'NAN' |
|
2115 ] ifFalse:[ |
|
2116 aStream nextPutAll:'nan' |
|
2117 ]. |
|
2118 count := count + 3. |
|
2119 ] ifFalse:[ |
|
2120 self < 0 ifTrue:[ |
|
2121 aStream nextPut:$-. |
|
2122 count := count + 1. |
|
2123 ] ifFalse:[ |
|
2124 showPositive ifTrue:[ |
|
2125 aStream nextPut:$+. |
|
2126 count := count + 1. |
|
2127 ] ifFalse:[ |
|
2128 sgn := false. |
|
2129 ]. |
|
2130 ]. |
|
2131 self = 0.0 ifTrue:[ |
|
2132 aStream nextPut:$0. |
|
2133 count := count + 1. |
|
2134 precision > 0 ifTrue:[ |
|
2135 aStream nextPut:$.. |
|
2136 count := count + 1. |
|
2137 precision timesRepeat:[ aStream nextPut:$0 ]. |
|
2138 count := count + precision. |
|
2139 ]. |
|
2140 self halt. |
|
2141 ] ifFalse:[ |
|
2142 |off d d_width_extra| |
|
2143 |
|
2144 "/ non-zero case |
|
2145 off := fixed |
|
2146 ifTrue:[ 1 + self abs log10 floor ] |
|
2147 ifFalse:[1]. |
|
2148 d := precision + off. |
|
2149 d_width_extra := d. |
|
2150 fixed ifTrue:[ |
|
2151 d_width_extra := 120 max:d. |
|
2152 ]. |
|
2153 "/ highly special case - fixed mode, precision is zero, abs(*this) < 1.0 |
|
2154 "/ without this trap a number like 0.9 printed fixed with 0 precision prints as 0 |
|
2155 "/ should be rounded to 1. |
|
2156 (fixed and:[ (precision == 0) and:[ (self abs < 1.0) ]]) ifTrue:[ |
|
2157 (self abs >= 0.5) ifTrue:[ |
|
2158 aStream nextPut:$1 |
|
2159 ] ifFalse:[ |
|
2160 aStream nextPut:$0 |
|
2161 ]. |
|
2162 ^ self |
|
2163 ]. |
|
2164 |
|
2165 "/ handle near zero to working precision (but not exactly zero) |
|
2166 (fixed and:[ d <= 0 ]) ifTrue:[ |
|
2167 aStream nextPut:$0. |
|
2168 (precision > 0) ifTrue:[ |
|
2169 aStream nextPut:$. . |
|
2170 aStream next:precision put:$0. |
|
2171 ] |
|
2172 ] ifFalse:[ |
|
2173 "/ default |
|
2174 |
|
2175 |t j| |
|
2176 |
|
2177 fixed ifTrue:[ |
|
2178 t := String streamContents:[:s | |
|
2179 self |
|
2180 printDigitsOn:s |
|
2181 precision:d_width_extra |
|
2182 exponentInto:[:e | exp := e] |
|
2183 ]. |
|
2184 ] ifFalse:[ |
|
2185 t := String streamContents:[:s | |
|
2186 self |
|
2187 printDigitsOn:s |
|
2188 precision:d |
|
2189 exponentInto:[:e | exp := e] |
|
2190 ]. |
|
2191 ]. |
|
2192 |
|
2193 fixed ifTrue:[ |
|
2194 "/ fix the string if it's been computed incorrectly |
|
2195 "/ round here in the decimal string if required |
|
2196 t := self round_string_qd:t at:(d + 1) offsetInto:[:o | off := o]. |
|
2197 |
|
2198 (off > 0) ifTrue:[ |
|
2199 aStream next:off putAll:t startingAt:0. |
|
2200 (precision > 0) ifTrue:[ |
|
2201 aStream nextPut:$. . |
|
2202 aStream next:precision putAll:t startingAt:off+1. |
|
2203 ] |
|
2204 ] ifFalse:[ |
|
2205 aStream nextPutAll:'0.'. |
|
2206 (off < 0) ifTrue:[ |
|
2207 aStream next:off negated put:$0. |
|
2208 ]. |
|
2209 aStream next:d putAll:t startingAt:0. |
|
2210 ] |
|
2211 ] ifFalse:[ |
|
2212 aStream nextPut:(t at:1). |
|
2213 (precision > 0) ifTrue:[ |
|
2214 aStream nextPut:$. . |
|
2215 ]. |
|
2216 aStream next:precision putAll:t startingAt:2. |
|
2217 ] |
|
2218 ]. |
|
2219 ]. |
1807 ] |
2220 ] |
1808 ]. |
2221 ]. |
1809 |
2222 |
1810 |
2223 "/ trap for improper offset with large values |
1811 " |
2224 "/ without this trap, output of values of the for 10^j - 1 fail for j > 28 |
1812 1.2345 asQDouble printDigitsOn:Transcript precision:5 exponentInto:[:e |] |
2225 "/ and are output with the point in the wrong place, leading to a dramatically off value |
1813 " |
2226 |
1814 |
2227 "/ (fixed and:[ (precision > 0) ]) ifTrue:[ |
1815 "Created: / 13-06-2017 / 17:28:08 / cg" |
2228 "/ "/ make sure that the value isn't dramatically larger |
|
2229 "/ from_string = atof(s.c_str()); |
|
2230 "/ |
|
2231 "/ // if this ratio is large, then we've got problems |
|
2232 "/ if( fabs( from_string / this->x[0] ) > 3.0 ){ |
|
2233 "/ |
|
2234 "/ int point_position; |
|
2235 "/ char temp; |
|
2236 "/ |
|
2237 "/ // loop on the string, find the point, move it up one |
|
2238 "/ // don't act on the first character |
|
2239 "/ for(i=1; i < s.length(); i++){ |
|
2240 "/ if(s[i] == '.'){ |
|
2241 "/ s[i] = s[i-1] ; |
|
2242 "/ s[i-1] = '.' ; |
|
2243 "/ break; |
|
2244 "/ } |
|
2245 "/ } |
|
2246 "/ |
|
2247 "/ from_string = atof(s.c_str()); |
|
2248 "/ // if this ratio is large, then the string has not been fixed |
|
2249 "/ if( fabs( from_string / this->x[0] ) > 3.0 ){ |
|
2250 "/ dd_real::error("Re-rounding unsuccessful in large number fixed point trap.") ; |
|
2251 "/ } |
|
2252 "/ } |
|
2253 "/ } |
|
2254 "/ |
|
2255 "/ if (!!fixed) { |
|
2256 "/ /* Fill in exponent part */ |
|
2257 "/ s += uppercase ? 'E' : 'e'; |
|
2258 "/ append_expn(s, e); |
|
2259 "/ } |
|
2260 "/ } |
|
2261 |
|
2262 "/ fill in the blanks |
|
2263 (delta := width-count) > 0 ifTrue:[ |
|
2264 self halt. |
|
2265 "/ if (fmt & ios_base::internal) { |
|
2266 "/ if (sgn) |
|
2267 "/ s.insert(static_cast<string::size_type>(1), delta, fill); |
|
2268 "/ else |
|
2269 "/ s.insert(static_cast<string::size_type>(0), delta, fill); |
|
2270 "/ } else if (fmt & ios_base::left) { |
|
2271 "/ s.append(delta, fill); |
|
2272 "/ } else { |
|
2273 "/ s.insert(static_cast<string::size_type>(0), delta, fill); |
|
2274 "/ } |
|
2275 "/ } |
|
2276 ]. |
|
2277 |
|
2278 "Created: / 15-06-2017 / 02:37:31 / cg" |
1816 ! |
2279 ! |
1817 |
2280 |
1818 printString |
2281 printString |
1819 "return a printed representation of the receiver" |
2282 "return a printed representation of the receiver" |
1820 |
2283 |
1821 self d1 = 0.0 ifTrue:[ |
2284 ^ String streamContents:[:s | self printOn:s] |
1822 ^ self d0 printString |
|
1823 ]. |
|
1824 ^ self d0 printString , '...' |
|
1825 |
2285 |
1826 "Created: / 12-06-2017 / 23:41:04 / cg" |
2286 "Created: / 12-06-2017 / 23:41:04 / cg" |
|
2287 "Modified: / 15-06-2017 / 01:53:46 / cg" |
1827 ! ! |
2288 ! ! |
1828 |
2289 |
1829 !QDouble methodsFor:'private accessing'! |
2290 !QDouble methodsFor:'private accessing'! |
1830 |
2291 |
1831 d0 |
2292 d0 |