Artifact bc2be77eacdb03df6b3ac2f65839338b2a773134d2c5c5c3449d2455403af4c9:
- Executable file
r37/lisp/csl/jlisp/LispFloat.java
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 15590) [annotate] [blame] [check-ins using] [more...]
// // This file is part of the Jlisp implementation of Standard Lisp // Copyright \u00a9 (C) Codemist Ltd, 1998-2000. // import java.io.*; import java.util.*; import java.math.*; class LispFloat extends LispNumber { double value; LispFloat(int value) { this.value = (double)value; } LispFloat(String value) { Double d = Double.valueOf(value); this.value = d.doubleValue(); } LispFloat(double value) { this.value = value; } LispObject eval() { return this; } void iprint() { String s = trimTo(Jlisp.printprec); if ((currentFlags & noLineBreak) == 0 && currentOutput.column + s.length() > currentOutput.lineLength) currentOutput.println(); currentOutput.print(s); } void blankprint() { String s = trimTo(Jlisp.printprec); if ((currentFlags & noLineBreak) == 0 && currentOutput.column + s.length() >= currentOutput.lineLength) currentOutput.println(); else currentOutput.print(" "); currentOutput.print(s); } // The next method is something that I am reasonably upset about since // I believe that Java ought to provide this sort of formatting but at // present I can not see how and where it does it. String trimTo(int n) // trim to n significant figures { if (n < 1) n = 1; else if (n > 16) n = 16; // limit precision to sensible range String s = Double.toString(value); //Jlisp.println("original = " + s); int len = s.length(); char [] s1 = s.toCharArray(); // identify and remove any "-" sign boolean neg = false; if (s1[0] == '-') { neg = true; for (int i=0; i<len-1; i++) s1[i] = s1[i+1]; len--; } //Jlisp.println("made +ve = " + new String(s1, 0, len)); // Extract an exponent if explicitly present int e = -1; for (int i=0; i<len; i++) { if (s1[i] == 'E') { e = i; break; } } int x = 0; if (e != -1) { String exponent = new String(s1, e+1, len-e-1); x = Integer.parseInt(exponent); len = e; } //Jlisp.println("exponent grabbed = " + new String(s1, 0, len) + " x= " + x); // Locate the decimal point, remove it, adjust exponent e = -1; for (int i=0; i<len; i++) { if (s1[i] == '.') { e = i; break; } } if (e != -1) { x -= (len - e - 1); for (int i=e; i<len-1; i++) s1[i] = s1[i+1]; len--; } //Jlisp.println("dot grabbed = " + new String(s1, 0, len) + " x= " + x); // Remove leading zeros (eg if original had been formated 0.0012345 while (len>0 && s1[0] == '0') { for (int i=0; i<len-1; i++) s1[i] = s1[i+1]; len--; } //Jlisp.println("no leading zero = " + new String(s1, 0, len) + " x= " + x); // Now the string s1 is digits of the number and x (an integer) is // an exponent (based on s being viewed as an integer). len is the // length of s1. neg is the sign. Eg an approximation to +pi might have // ended up as // s1 = "314158" // len = 6 // neg = false // x = -5 // My next job is to round to n places... If I do not have that many // present I do not have anything to do! if (n < len) { char next = s1[n]; // thing to test against '5' x = x + len - n; len = n; // Some people would round by detecting the case that the digits to be // disarded were exactly 50000.. and in that mid-way case they might // round to yield an even or odd result. At present I do the simple // thing and round up on any fraction >= 0.5. //Jlisp.println("truncated = " + new String(s1, 0, len) + " x= " + x); if (next >= '5') // need to round up? { char w = 'x'; for (int k=len-1; k >= 0; k--) { w = s1[k]; w = (char)(w == '9' ? '0' : w + 1); s1[k] = w; if (w != '0') break; } // If the number being rounded (say to 5 places) had been 999997 then // rounding converts it to (1)00000. The "1" would in natural cases go // into s1[-1], but in this case I KNOW that all remaining digits in s1 // are "0" so I can safely put it in s1[0]! I then have to adjust the // exponent to reflect the shift. if (w == '0') { s1[0] = '1'; x++; } } } //Jlisp.println("rounded = " + new String(s1, 0, len) + " x= " + x); // Now I guess I can trim any trailing zeros while (len>0 && s1[len-1] == '0') { len--; x++; } //Jlisp.println("no trailing 0 = " + new String(s1, 0, len) + " x= " + x); // Finally I can try to decide on a format to use (F or E style) // and reconstruct the result as a string if (len == 0) return "0.0"; // easy special case! StringBuffer r = new StringBuffer(); if (neg) r.append("-"); if (x>n || x<(-len-2)) // use "E" style { r.append(s1[0]); r.append("."); if (len == 1) r.append("0"); else r.append(s1, 1, len-1); r.append("e"); r.append(x+len-1); } else // use "F" style { int left = len; if (len+x <= 0) r.append("0"); else { if (x > 0) { r.append(s1, 0, len); while (x > 0) { r.append("0"); x--; } left = 0; } else { r.append(s1, 0, len+x); left -= (len+x); } } r.append("."); if (left == 0) r.append("0"); else { while (len+x < 0) { r.append("0"); len++; } r.append(s1, len+x, left); } } //Jlisp.println("result = " + r.toString()); return r.toString(); } double doubleValue() { return value; } public boolean lispequals(Object b) { if (!(b instanceof LispFloat)) return false; return value == ((LispFloat)b).value; } public boolean equals(Object b) { if (!(b instanceof LispFloat)) return false; return value == ((LispFloat)b).value; } public int lisphashCode() { return (new Double(value)).hashCode(); } public int hashCode() { return (new Double(value)).hashCode(); } void scan() { Object w = new Double(value); if (Jlisp.objects.contains(w)) // seen before? { if (!Jlisp.repeatedObjects.containsKey(w)) { Jlisp.repeatedObjects.put( w, Jlisp.nil); // value is junk at this stage } } else Jlisp.objects.add(w); } void dump() throws IOException { Object d = new Double(value); Object w = Jlisp.repeatedObjects.get(d); if (w != null && w instanceof Integer) putSharedRef(w); // processed before else { if (w != null) // will be used again sometime { Jlisp.repeatedObjects.put( d, new Integer(Jlisp.sharedIndex++)); Jlisp.odump.write(X_STORE); } long rep = Double.doubleToLongBits(value); Jlisp.odump.write(X_DOUBLE); for (int i=0; i<8; i++) { Jlisp.odump.write((int)(rep >> (56-8*i))); } } } public LispObject negate() throws Exception { return new LispFloat(-value); } public LispObject abs() throws Exception { if (value >= 0) return this; else return new LispFloat(-value); } public LispObject add(LispObject a) throws Exception { return new LispFloat(value + a.doubleValue()); } public LispObject subtract(LispObject a) throws Exception { return new LispFloat(value - a.doubleValue()); } public LispObject multiply(LispObject a) throws Exception { return new LispFloat(value * a.doubleValue()); } public LispObject divide(LispObject a) throws Exception { return new LispFloat(value / a.doubleValue()); } public LispObject remainder(LispObject a) throws Exception { return new LispFloat(value % a.doubleValue()); } public LispObject expt(LispObject a) throws Exception { // it is possible that I should delect cases where a is an integer // and raise to a power using some alternative scheme, like repeated // multiplication. return new LispFloat(Math.pow(value, a.doubleValue())); } public LispObject max(LispObject a) throws Exception { return (value >= a.doubleValue() ? this : a); } public LispObject min(LispObject a) throws Exception { return (value <= a.doubleValue() ? this : a); } boolean eqn(LispObject a) throws Exception { return (value == a.doubleValue()); } boolean neqn(LispObject a) throws Exception { return (value != a.doubleValue()); } boolean ge(LispObject a) throws Exception { return (value > a.doubleValue()); } boolean geq(LispObject a) throws Exception { return (value >= a.doubleValue()); } boolean le(LispObject a) throws Exception { return (value < a.doubleValue()); } boolean leq(LispObject a) throws Exception { return (value <= a.doubleValue()); } public LispObject add1() throws Exception { return new LispFloat(value + 1.0); } public LispObject sub1() throws Exception { return new LispFloat(value - 1.0); } public LispObject floor() throws Exception { BigDecimal w = new BigDecimal(value).setScale(0, BigDecimal.ROUND_FLOOR); return LispInteger.valueOf(w.toBigInteger()); } public LispObject ceiling() throws Exception { BigDecimal w = new BigDecimal(value).setScale(0, BigDecimal.ROUND_CEILING); return LispInteger.valueOf(w.toBigInteger()); } public LispObject round() throws Exception { BigDecimal w = new BigDecimal(value).setScale(0, BigDecimal.ROUND_HALF_EVEN); return LispInteger.valueOf(w.toBigInteger()); } public LispObject truncate() throws Exception { BigDecimal w = new BigDecimal(value).setScale(0, BigDecimal.ROUND_DOWN); return LispInteger.valueOf(w.toBigInteger()); } public LispObject fix() throws Exception { BigDecimal w = new BigDecimal(value).setScale(0, BigDecimal.ROUND_DOWN); return LispInteger.valueOf(w.toBigInteger()); } public LispObject fixp() throws Exception { return Jlisp.nil; } public LispObject integerp() throws Exception { return Jlisp.nil; } public LispObject jfloat() throws Exception { return this; } public LispObject floatp() throws Exception { return Jlisp.lispTrue; } public LispObject minusp() throws Exception { return (value < 0.0) ? Jlisp.lispTrue : Jlisp.nil; } public LispObject plusp() throws Exception { return (value >= 0.0) ? Jlisp.lispTrue : Jlisp.nil; } public LispObject zerop() throws Exception { return (value == 0.0) ? Jlisp.lispTrue : Jlisp.nil; } public LispObject onep() throws Exception { return (value == 1.0) ? Jlisp.lispTrue : Jlisp.nil; } LispObject addInteger(LispBigInteger a) throws Exception { return new LispFloat(a.value.doubleValue() + value); } LispObject subtractInteger(LispBigInteger a) throws Exception { return new LispFloat(a.value.doubleValue() - value); } LispObject multiplyInteger(LispBigInteger a) throws Exception { return new LispFloat(a.value.doubleValue() * value); } LispObject divideInteger(LispBigInteger a) throws Exception { return new LispFloat(a.value.doubleValue() / value); } LispObject remainderInteger(LispBigInteger a) throws Exception { return new LispFloat(a.value.doubleValue() % value); } LispObject maxInteger(LispBigInteger a) throws Exception { if (a.value.doubleValue() >= value) return a; else return this; } LispObject exptInteger(LispBigInteger a) throws Exception { return new LispFloat(Math.pow(a.doubleValue(), value)); } LispObject minInteger(LispBigInteger a) throws Exception { if (a.value.doubleValue() <= value) return a; else return this; } boolean eqnInteger(LispBigInteger a) throws Exception { return (a.value.doubleValue() == value); } boolean neqnInteger(LispBigInteger a) throws Exception { return (a.value.doubleValue() != value); } boolean geInteger(LispBigInteger a) throws Exception { return (a.value.doubleValue() > value); } boolean geqInteger(LispBigInteger a) throws Exception { return (a.value.doubleValue() >= value); } boolean leInteger(LispBigInteger a) throws Exception { return (a.value.doubleValue() < value); } boolean leqInteger(LispBigInteger a) throws Exception { return (a.value.doubleValue() <= value); } LispObject addSmallInteger(LispSmallInteger a) throws Exception { return new LispFloat((double)a.value + value); } LispObject subtractSmallInteger(LispSmallInteger a) throws Exception { return new LispFloat((double)a.value - value); } LispObject multiplySmallInteger(LispSmallInteger a) throws Exception { return new LispFloat((double)a.value * value); } LispObject divideSmallInteger(LispSmallInteger a) throws Exception { return new LispFloat((double)a.value / value); } LispObject remainderSmallInteger(LispSmallInteger a) throws Exception { return new LispFloat((double)a.value % value); } LispObject maxSmallInteger(LispSmallInteger a) throws Exception { if ((double)a.value >= value) return a; else return this; } LispObject exptSmallInteger(LispSmallInteger a) throws Exception { return new LispFloat(Math.pow(a.doubleValue(), value)); } LispObject minSmallInteger(LispSmallInteger a) throws Exception { if ((double)a.value <= value) return a; else return this; } boolean eqnSmallInteger(LispSmallInteger a) throws Exception { return ((double)a.value == value); } boolean neqnSmallInteger(LispSmallInteger a) throws Exception { return ((double)a.value != value); } boolean geSmallInteger(LispSmallInteger a) throws Exception { return ((double)a.value > value); } boolean geqSmallInteger(LispSmallInteger a) throws Exception { return ((double)a.value >= value); } boolean leSmallInteger(LispSmallInteger a) throws Exception { return ((double)a.value < value); } boolean leqSmallInteger(LispSmallInteger a) throws Exception { return ((double)a.value <= value); } } // end of LispFloat.java