OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [native/] [jni/] [java-lang/] [java_lang_VMDouble.c] - Blame information for rev 774

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.