-
-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
329: Retain floating point precision when converting floats #331
Changes from all commits
903a961
a05c13b
faa269f
c0a5e9a
d05aff2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -247,10 +247,10 @@ public Number reciprocal(Number number) { | |
return ((RationalNumber) number).reciprocal(); | ||
} | ||
if(number instanceof Double) { | ||
return RationalNumber.of((double)number).reciprocal(); | ||
return RationalNumber.of(number.doubleValue()).reciprocal(); | ||
} | ||
if(number instanceof Float) { | ||
return RationalNumber.of(number.doubleValue()).reciprocal(); | ||
return RationalNumber.of(number.floatValue()).reciprocal(); | ||
} | ||
throw unsupportedNumberType(number); | ||
} | ||
|
@@ -615,7 +615,7 @@ private BigDecimal toBigDecimal(Number number) { | |
return BigDecimal.valueOf(number.longValue()); | ||
} | ||
if(number instanceof Double || number instanceof Float) { | ||
return BigDecimal.valueOf(number.doubleValue()); | ||
return new BigDecimal(number.toString()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not convert floats to String and then to BigDecimal if the general scheme (as up for discussion in #332) is to first properly extend floats to double before converting to BigDecimal. If we agree on this scheme we should be consistent with it throughout the entire implementation. |
||
} | ||
if(number instanceof RationalNumber) { | ||
throw unexpectedCodeReach(); | ||
|
@@ -668,7 +668,7 @@ private Number addWideAndNarrow( | |
} | ||
|
||
if(narrow instanceof Double || narrow instanceof Float) { | ||
return ((BigDecimal) wide).add(BigDecimal.valueOf(narrow.doubleValue()), Calculus.MATH_CONTEXT); | ||
return ((BigDecimal) wide).add(new BigDecimal(narrow.toString()), Calculus.MATH_CONTEXT); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dito: consistency |
||
} | ||
|
||
if(narrow instanceof RationalNumber) { | ||
|
@@ -685,23 +685,23 @@ private Number addWideAndNarrow( | |
|
||
if(narrow instanceof Double || narrow instanceof Float) { | ||
//converting to BigDecimal, because especially fractional addition is sensitive to precision loss | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
.add(BigDecimal.valueOf(narrow.doubleValue())); | ||
return new BigDecimal(wide.toString()) | ||
.add(new BigDecimal(narrow.toString())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dito: consistency |
||
} | ||
|
||
if(narrow instanceof RationalNumber) { | ||
//TODO[220] can we do better than that, eg. by converting BigDecimal to RationalNumber | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point wide is potentially a float, so don't break consistency. |
||
.add(((RationalNumber) narrow).bigDecimalValue()); | ||
} | ||
|
||
if(narrow instanceof BigInteger) { | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dito: consistency |
||
.add(new BigDecimal((BigInteger) narrow)); | ||
} | ||
|
||
// at this point we know, that 'narrow' is one of {(Atomic)Long, (Atomic)Integer, Short, Byte} | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point wide is potentially a float, so don't break consistency. |
||
.add(BigDecimal.valueOf(narrow.longValue())); | ||
|
||
} | ||
|
@@ -748,7 +748,7 @@ private Number multiplyWideAndNarrow( | |
} | ||
|
||
if(narrow instanceof Double || narrow instanceof Float) { | ||
return ((BigDecimal) wide).multiply(BigDecimal.valueOf(narrow.doubleValue()), Calculus.MATH_CONTEXT); | ||
return ((BigDecimal) wide).multiply(new BigDecimal(narrow.toString()), Calculus.MATH_CONTEXT); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dito: consistency |
||
} | ||
|
||
if(narrow instanceof RationalNumber) { | ||
|
@@ -765,23 +765,28 @@ private Number multiplyWideAndNarrow( | |
|
||
if(narrow instanceof Double || narrow instanceof Float) { | ||
// not converting to BigDecimal, because fractional multiplication is not sensitive to precision loss | ||
return wide.doubleValue() * narrow.doubleValue(); | ||
if (wide instanceof Float && narrow instanceof Float) { | ||
// return float if both are floats | ||
return wide.floatValue() * narrow.floatValue(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not do that, as by extension to double we can guarantee the float value multiplication not to overflow. Its a corner case granted, but why risk that? |
||
} else { | ||
return wide.doubleValue() * narrow.doubleValue(); | ||
} | ||
} | ||
|
||
if(narrow instanceof RationalNumber) { | ||
//TODO[220] can we do better than that, eg. by converting BigDecimal to RationalNumber | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point wide is potentially a float, so don't break consistency. |
||
.multiply(((RationalNumber) narrow).bigDecimalValue()); | ||
} | ||
|
||
if(narrow instanceof BigInteger) { | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dito: consistency |
||
.multiply(new BigDecimal((BigInteger) narrow)); | ||
} | ||
|
||
// at this point we know, that 'narrow' is one of {(Atomic)Long, (Atomic)Integer, Short, Byte} | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
.multiply(BigDecimal.valueOf(narrow.longValue())); | ||
return new BigDecimal(wide.toString()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point wide is potentially a float, so don't break consistency. |
||
.multiply(BigDecimal.valueOf(narrow.longValue())); | ||
|
||
} | ||
|
||
|
@@ -821,7 +826,7 @@ private int compareWideVsNarrow( | |
} | ||
|
||
if(narrow instanceof Double || narrow instanceof Float) { | ||
return ((BigDecimal) wide).compareTo(BigDecimal.valueOf(narrow.doubleValue())); | ||
return ((BigDecimal) wide).compareTo(new BigDecimal(narrow.toString())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dito: consistency |
||
} | ||
|
||
if(narrow instanceof RationalNumber) { | ||
|
@@ -837,22 +842,23 @@ private int compareWideVsNarrow( | |
// at this point we know, that wide is one of {Double, Float} | ||
|
||
if(narrow instanceof Double || narrow instanceof Float) { | ||
return Double.compare(wide.doubleValue(), narrow.doubleValue()); | ||
return new BigDecimal(wide.toString()) | ||
.compareTo(new BigDecimal(narrow.toString())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dito: consistency |
||
} | ||
|
||
if(narrow instanceof RationalNumber) { | ||
//TODO[220] can we do better than that, eg. by converting BigDecimal to RationalNumber | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
.compareTo(((RationalNumber) narrow).bigDecimalValue()); | ||
} | ||
|
||
if(narrow instanceof BigInteger) { | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
.compareTo(new BigDecimal((BigInteger) narrow)); | ||
} | ||
|
||
// at this point we know, that 'narrow' is one of {(Atomic)Long, (Atomic)Integer, Short, Byte} | ||
return BigDecimal.valueOf(wide.doubleValue()) | ||
return new BigDecimal(wide.toString()) | ||
.compareTo(BigDecimal.valueOf(narrow.longValue())); | ||
|
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -123,6 +123,18 @@ public static RationalNumber of(double number) { | |
return of(decimalValue); | ||
} | ||
|
||
/** | ||
* Returns a {@code RationalNumber} that represents the given float | ||
* {@code number}, with an accuracy equivalent to {@code new BigDecimal(Float.toString(number))}. | ||
* | ||
* @param number | ||
*/ | ||
public static RationalNumber of(float number) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned above, breaks the general scheme of first extending floats to double before converting them to BigDecimal or Rational. |
||
// smh why does Java not have BigDecimal.valueOf(float) ?! | ||
final BigDecimal decimalValue = new BigDecimal(Float.toString(number)); | ||
return of(decimalValue); | ||
} | ||
|
||
/** | ||
* Returns a {@code RationalNumber} that represents the given BigDecimal decimalValue. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not introduce a RationalNumber.of(float) for the reasons discussed in (#332).