java_lang_VMDouble.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. /* VMDouble.c - java.lang.VMDouble native functions
  2. Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006, 2007
  3. Free Software Foundation, Inc.
  4. This file is part of GNU Classpath.
  5. GNU Classpath is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9. GNU Classpath is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GNU Classpath; see the file COPYING. If not, write to the
  15. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. 02110-1301 USA.
  17. Linking this library statically or dynamically with other modules is
  18. making a combined work based on this library. Thus, the terms and
  19. conditions of the GNU General Public License cover the whole
  20. combination.
  21. As a special exception, the copyright holders of this library give you
  22. permission to link this library with independent modules to produce an
  23. executable, regardless of the license terms of these independent
  24. modules, and to copy and distribute the resulting executable under
  25. terms of your choice, provided that you also meet, for each linked
  26. independent module, the terms and conditions of the license of that
  27. module. An independent module is a module which is not derived from
  28. or based on this library. If you modify this library, you may extend
  29. this exception to your version of the library, but you are not
  30. obligated to do so. If you do not wish to do so, delete this
  31. exception statement from your version. */
  32. #include <assert.h>
  33. #include <config.h>
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include "mprec.h"
  38. #include "fdlibm.h"
  39. #include "jcl.h"
  40. #include "java_lang_VMDouble.h"
  41. static jclass clsDouble;
  42. static jmethodID isNaNID;
  43. static jdouble NEGATIVE_INFINITY;
  44. static jdouble POSITIVE_INFINITY;
  45. static jdouble NaN;
  46. /*
  47. * Class: java_lang_VMDouble
  48. * Method: initIDs
  49. * Signature: ()V
  50. */
  51. JNIEXPORT void JNICALL
  52. Java_java_lang_VMDouble_initIDs (JNIEnv * env, jclass cls __attribute__ ((__unused__)))
  53. {
  54. jfieldID negInfID;
  55. jfieldID posInfID;
  56. jfieldID nanID;
  57. clsDouble = (*env)->FindClass (env, "java/lang/Double");
  58. if (clsDouble == NULL)
  59. {
  60. DBG ("unable to get class java.lang.Double\n") return;
  61. }
  62. clsDouble = (*env)->NewGlobalRef(env, clsDouble);
  63. if (clsDouble == NULL)
  64. {
  65. DBG ("unable to register class java.lang.Double as global ref\n") return;
  66. }
  67. isNaNID = (*env)->GetStaticMethodID (env, clsDouble, "isNaN", "(D)Z");
  68. if (isNaNID == NULL)
  69. {
  70. DBG ("unable to determine method id of isNaN\n") return;
  71. }
  72. negInfID = (*env)->GetStaticFieldID (env, clsDouble, "NEGATIVE_INFINITY", "D");
  73. if (negInfID == NULL)
  74. {
  75. DBG ("unable to determine field id of NEGATIVE_INFINITY\n") return;
  76. }
  77. posInfID = (*env)->GetStaticFieldID (env, clsDouble, "POSITIVE_INFINITY", "D");
  78. if (posInfID == NULL)
  79. {
  80. DBG ("unable to determine field id of POSITIVE_INFINITY\n") return;
  81. }
  82. nanID = (*env)->GetStaticFieldID (env, clsDouble, "NaN", "D");
  83. if (posInfID == NULL)
  84. {
  85. DBG ("unable to determine field id of NaN\n") return;
  86. }
  87. POSITIVE_INFINITY = (*env)->GetStaticDoubleField (env, clsDouble, posInfID);
  88. NEGATIVE_INFINITY = (*env)->GetStaticDoubleField (env, clsDouble, negInfID);
  89. NaN = (*env)->GetStaticDoubleField (env, clsDouble, nanID);
  90. #ifdef DEBUG
  91. fprintf (stderr, "java.lang.Double.initIDs() POSITIVE_INFINITY = %g\n",
  92. POSITIVE_INFINITY);
  93. fprintf (stderr, "java.lang.Double.initIDs() NEGATIVE_INFINITY = %g\n",
  94. NEGATIVE_INFINITY);
  95. fprintf (stderr, "java.lang.Double.initIDs() NaN = %g\n", NaN);
  96. #endif
  97. }
  98. /*
  99. * Class: java_lang_VMDouble
  100. * Method: doubleToRawLongBits
  101. * Signature: (D)J
  102. */
  103. JNIEXPORT jlong JNICALL
  104. Java_java_lang_VMDouble_doubleToRawLongBits
  105. (JNIEnv * env __attribute__ ((__unused__)),
  106. jclass cls __attribute__ ((__unused__)), jdouble doubleValue)
  107. {
  108. jvalue val;
  109. val.d = doubleValue;
  110. #if defined(__IEEE_BYTES_LITTLE_ENDIAN)
  111. /* On little endian ARM processors when using FPA, word order of
  112. doubles is still big endian. So take that into account here. When
  113. using VFP, word order of doubles follows byte order. */
  114. #define SWAP_DOUBLE(a) (((a) << 32) | (((a) >> 32) & 0x00000000ffffffff))
  115. val.j = SWAP_DOUBLE(val.j);
  116. #endif
  117. return val.j;
  118. }
  119. /*
  120. * Class: java_lang_VMDouble
  121. * Method: longBitsToDouble
  122. * Signature: (J)D
  123. */
  124. JNIEXPORT jdouble JNICALL
  125. Java_java_lang_VMDouble_longBitsToDouble
  126. (JNIEnv * env __attribute__ ((__unused__)),
  127. jclass cls __attribute__ ((__unused__)), jlong longValue)
  128. {
  129. jvalue val;
  130. val.j = longValue;
  131. #if defined(__IEEE_BYTES_LITTLE_ENDIAN)
  132. val.j = SWAP_DOUBLE(val.j);
  133. #endif
  134. return val.d;
  135. }
  136. /**
  137. * Parse a double from a char array.
  138. */
  139. static jdouble
  140. parseDoubleFromChars(JNIEnv * env, const char * buf)
  141. {
  142. char *endptr;
  143. jdouble val = 0.0;
  144. const char *p = buf, *end, *last_non_ws, *temp;
  145. int ok = 1;
  146. #ifdef DEBUG
  147. fprintf (stderr, "java.lang.VMDouble.parseDouble (%s)\n", buf);
  148. #endif
  149. /* Trim the buffer, similar to String.trim(). First the leading
  150. characters. */
  151. while (*p && *p <= ' ')
  152. ++p;
  153. /* Find the last non-whitespace character. This method is safe
  154. even with multi-byte UTF-8 characters. */
  155. end = p;
  156. last_non_ws = NULL;
  157. while (*end)
  158. {
  159. if (*end > ' ')
  160. last_non_ws = end;
  161. ++end;
  162. }
  163. if (last_non_ws == NULL)
  164. last_non_ws = p + strlen (p);
  165. else
  166. {
  167. /* Skip past the last non-whitespace character. */
  168. ++last_non_ws;
  169. }
  170. /* Check for infinity and NaN */
  171. temp = p;
  172. if (temp[0] == '+' || temp[0] == '-')
  173. temp++;
  174. if (strncmp ("Infinity", temp, (size_t) 8) == 0)
  175. {
  176. if (p[0] == '-')
  177. return NEGATIVE_INFINITY;
  178. return POSITIVE_INFINITY;
  179. }
  180. if (strncmp ("NaN", temp, (size_t) 3) == 0)
  181. return NaN;
  182. /* Skip a trailing `f' or `d'. */
  183. if (last_non_ws > p
  184. && (last_non_ws[-1] == 'f'
  185. || last_non_ws[-1] == 'F'
  186. || last_non_ws[-1] == 'd' || last_non_ws[-1] == 'D'))
  187. --last_non_ws;
  188. if (last_non_ws > p)
  189. {
  190. struct _Jv_reent reent;
  191. memset (&reent, 0, sizeof reent);
  192. val = _strtod_r (&reent, p, &endptr);
  193. #ifdef DEBUG
  194. fprintf (stderr, "java.lang.VMDouble.parseDouble val = %g\n", val);
  195. fprintf (stderr, "java.lang.VMDouble.parseDouble %p != %p ???\n",
  196. endptr, last_non_ws);
  197. #endif
  198. if (endptr != last_non_ws)
  199. ok = 0;
  200. }
  201. else
  202. ok = 0;
  203. if (!ok)
  204. {
  205. val = 0.0;
  206. JCL_ThrowException (env,
  207. "java/lang/NumberFormatException",
  208. "unable to parse double");
  209. }
  210. return val;
  211. }
  212. #define MAXIMAL_DECIMAL_STRING_LENGTH 64
  213. /**
  214. * Use _dtoa to print a double or a float as a string with the given precision.
  215. */
  216. static void
  217. dtoa_toString
  218. (char * buffer, jdouble value, jint precision, jboolean isFloat)
  219. {
  220. const int DTOA_MODE = 2;
  221. char result[MAXIMAL_DECIMAL_STRING_LENGTH];
  222. int decpt, sign;
  223. char *s, *d;
  224. int i;
  225. /* use mode 2 to get at the digit stream, all other modes are useless
  226. *
  227. * since mode 2 only gives us as many digits as we need in precision, we need to
  228. * add the digits in front of the floating point to it, if there is more than one
  229. * to be printed. That's the case if the value is going to be printed using the
  230. * normal notation, i.e. if it is 0 or >= 1.0e-3 and < 1.0e7.
  231. */
  232. int digits_in_front_of_floating_point = ceil(log10(value));
  233. if (digits_in_front_of_floating_point > 1 && digits_in_front_of_floating_point < 7)
  234. precision += digits_in_front_of_floating_point;
  235. _dtoa (value, DTOA_MODE, precision, &decpt, &sign, NULL, buffer, (int) isFloat);
  236. value = fabs (value);
  237. s = buffer;
  238. d = result;
  239. /* Handle negative sign */
  240. if (sign)
  241. *d++ = '-';
  242. /* Handle normal represenation */
  243. if ((value >= 1e-3 && value < 1e7) || (value == 0))
  244. {
  245. if (decpt <= 0)
  246. *d++ = '0';
  247. else
  248. {
  249. for (i = 0; i < decpt; i++)
  250. if (*s)
  251. *d++ = *s++;
  252. else
  253. *d++ = '0';
  254. }
  255. *d++ = '.';
  256. if (*s == 0)
  257. {
  258. *d++ = '0';
  259. decpt++;
  260. }
  261. while (decpt++ < 0)
  262. *d++ = '0';
  263. while (*s)
  264. *d++ = *s++;
  265. *d = 0;
  266. }
  267. /* Handle scientific representaiton */
  268. else
  269. {
  270. *d++ = *s++;
  271. decpt--;
  272. *d++ = '.';
  273. if (*s == 0)
  274. *d++ = '0';
  275. while (*s)
  276. *d++ = *s++;
  277. *d++ = 'E';
  278. if (decpt < 0)
  279. {
  280. *d++ = '-';
  281. decpt = -decpt;
  282. }
  283. {
  284. char exp[4];
  285. char *e = exp + sizeof exp;
  286. *--e = 0;
  287. do
  288. {
  289. *--e = '0' + decpt % 10;
  290. decpt /= 10;
  291. }
  292. while (decpt > 0);
  293. while (*e)
  294. *d++ = *e++;
  295. }
  296. *d = 0;
  297. }
  298. /* copy the result into the buffer */
  299. memcpy(buffer, result, MAXIMAL_DECIMAL_STRING_LENGTH);
  300. }
  301. /*
  302. * Class: java_lang_VMDouble
  303. * Method: toString
  304. * Signature: (DZ)Ljava/lang/String;
  305. */
  306. JNIEXPORT jstring JNICALL
  307. Java_java_lang_VMDouble_toString
  308. (JNIEnv * env, jclass cls __attribute__ ((__unused__)), jdouble value, jboolean isFloat)
  309. {
  310. char buf[MAXIMAL_DECIMAL_STRING_LENGTH];
  311. const jint MAXIMAL_FLOAT_PRECISION = 10;
  312. const jint MAXIMAL_DOUBLE_PRECISION = 19;
  313. jint maximal_precision;
  314. jint least_necessary_precision = 2;
  315. jboolean parsed_value_unequal;
  316. if ((*env)->CallStaticBooleanMethod (env, clsDouble, isNaNID, value))
  317. return (*env)->NewStringUTF (env, "NaN");
  318. if (value == POSITIVE_INFINITY)
  319. return (*env)->NewStringUTF (env, "Infinity");
  320. if (value == NEGATIVE_INFINITY)
  321. return (*env)->NewStringUTF (env, "-Infinity");
  322. if (isFloat)
  323. maximal_precision = MAXIMAL_FLOAT_PRECISION;
  324. else
  325. maximal_precision = MAXIMAL_DOUBLE_PRECISION;
  326. /* Try to find the 'good enough' precision,
  327. * that results in enough digits being printed to be able to
  328. * convert the number back into the original double, but no
  329. * further digits.
  330. */
  331. do {
  332. jdouble parsed_value;
  333. assert(least_necessary_precision <= maximal_precision);
  334. /* Convert the value to a string and back. */
  335. dtoa_toString(buf, value, least_necessary_precision, isFloat);
  336. parsed_value = parseDoubleFromChars(env, buf);
  337. /* Check whether the original value, and the value after conversion match. */
  338. /* We need to cast floats to float to make sure that our ineqality check works
  339. * well for floats as well as for doubles.
  340. */
  341. parsed_value_unequal = ( isFloat ?
  342. (float) parsed_value != (float) value :
  343. parsed_value != value);
  344. least_necessary_precision++;
  345. }
  346. while (parsed_value_unequal);
  347. return (*env)->NewStringUTF (env, buf);
  348. }
  349. /*
  350. * Class: java_lang_VMDouble
  351. * Method: parseDouble
  352. * Signature: (Ljava/lang/String;)D
  353. */
  354. JNIEXPORT jdouble JNICALL
  355. Java_java_lang_VMDouble_parseDouble
  356. (JNIEnv * env, jclass cls __attribute__ ((__unused__)), jstring str)
  357. {
  358. jboolean isCopy;
  359. const char *buf;
  360. jdouble val = 0.0;
  361. if (str == NULL)
  362. {
  363. JCL_ThrowException (env, "java/lang/NullPointerException", "null");
  364. return val;
  365. }
  366. buf = (*env)->GetStringUTFChars (env, str, &isCopy);
  367. if (buf == NULL)
  368. {
  369. /* OutOfMemoryError already thrown */
  370. }
  371. else
  372. {
  373. val = parseDoubleFromChars(env, buf);
  374. (*env)->ReleaseStringUTFChars (env, str, buf);
  375. }
  376. return val;
  377. }