هل هناك ما يعادل جافا من FREXP؟
-
20-09-2019 - |
سؤال
هل هناك ما يعادل Java من وظيفة C / C ++ المسمى Frexp؟ إذا لم تكن مألوفًا ، فهو FREXP حددها ويكيبيديا إلى "كسر رقم النقطة لأسفل إلى Mantissa و Provonent."
أنا أبحث عن تنفيذ مع كل من السرعة والدقة ، لكنني أفضل أن أحصل على الدقة إذا كان بإمكاني اختيار واحدة فقط.
هذه هي عينة الكود من المرجع الأول. يجب أن يجعل عقد FREXP أكثر وضوحًا:
/* frexp example */
#include <stdio.h>
#include <math.h>
int main ()
{
double param, result;
int n;
param = 8.0;
result = frexp (param , &n);
printf ("%lf * 2^%d = %f\n", result, n, param);
return 0;
}
/* Will produce: 0.500000 * 2^4 = 8.000000 */
المحلول
كيف هذا؟
public static class FRexpResult
{
public int exponent = 0;
public double mantissa = 0.;
}
public static FRexpResult frexp(double value)
{
final FRexpResult result = new FRexpResult();
long bits = Double.doubleToLongBits(value);
double realMant = 1.;
// Test for NaN, infinity, and zero.
if (Double.isNaN(value) ||
value + value == value ||
Double.isInfinite(value))
{
result.exponent = 0;
result.mantissa = value;
}
else
{
boolean neg = (bits < 0);
int exponent = (int)((bits >> 52) & 0x7ffL);
long mantissa = bits & 0xfffffffffffffL;
if(exponent == 0)
{
exponent++;
}
else
{
mantissa = mantissa | (1L<<52);
}
// bias the exponent - actually biased by 1023.
// we are treating the mantissa as m.0 instead of 0.m
// so subtract another 52.
exponent -= 1075;
realMant = mantissa;
// normalize
while(realMant > 1.0)
{
mantissa >>= 1;
realMant /= 2.;
exponent++;
}
if(neg)
{
realMant = realMant * -1;
}
result.exponent = exponent;
result.mantissa = realMant;
}
return result;
}
هذا "مستوحى" أو تم نسخه بشكل متطابق تقريبًا من إجابه إلى سؤال مماثل C#. إنه يعمل مع البتات ثم يجعل Mantissa رقم بين 1.0 و 0.0.
نصائح أخرى
انظر float.floattointbits و double.doubletolongbits. لا تزال بحاجة إلى القليل من المنطق الإضافي لفك تشفير IEEE 754 نقطة عائمة.
هذا يفعل ما تريد.
public class Test {
public class FRex {
public FRexPHolder frexp (double value) {
FRexPHolder ret = new FRexPHolder();
ret.exponent = 0;
ret.mantissa = 0;
if (value == 0.0 || value == -0.0) {
return ret;
}
if (Double.isNaN(value)) {
ret.mantissa = Double.NaN;
ret.exponent = -1;
return ret;
}
if (Double.isInfinite(value)) {
ret.mantissa = value;
ret.exponent = -1;
return ret;
}
ret.mantissa = value;
ret.exponent = 0;
int sign = 1;
if (ret.mantissa < 0f) {
sign--;
ret.mantissa = -(ret.mantissa);
}
while (ret.mantissa < 0.5f) {
ret.mantissa *= 2.0f;
ret.exponent -= 1;
}
while (ret.mantissa >= 1.0f) {
ret.mantissa *= 0.5f;
ret.exponent++;
}
ret.mantissa *= sign;
return ret;
}
}
public class FRexPHolder {
int exponent;
double mantissa;
}
public static void main(String args[]) {
new Test();
}
public Test() {
double value = 8.0;
//double value = 0.0;
//double value = -0.0;
//double value = Double.NaN;
//double value = Double.NEGATIVE_INFINITY;
//double value = Double.POSITIVE_INFINITY;
FRex test = new FRex();
FRexPHolder frexp = test.frexp(value);
System.out.println("Mantissa: " + frexp.mantissa);
System.out.println("Exponent: " + frexp.exponent);
System.out.println("Original value was: " + value);
System.out.println(frexp.mantissa+" * 2^" + frexp.exponent + " = ");
System.out.println(frexp.mantissa*(1<<frexp.exponent));
}
}
إذا كنت أقرأ هذا بشكل صحيح ...
public class Frexp {
public static void main (String[] args)
{
double param, result;
int n;
param = 8.0;
n = Math.getExponent(param);
//result = ??
System.out.printf ("%f * 2^%d = %f\n", result, n, param);
}
}
لسوء الحظ ، لا يبدو أن هناك طريقة مدمجة للحصول على Mantissa دون تحويلها إلى BigDecimal أولاً (أو مجرد القيام بالقسمة: result = param / Math.pow(2,n)
.
غريب كفاية، scalb
هل العكس تمامًا: خذ mantissa وأسعد وتوليد تعويم جديد منه.
لست على دراية بوظيفة FREXP ، لكنني أعتقد أنك بحاجة إلى النظر إلى BigDecimal'القيم المقيدة وغير المنقوقة. "Uncaled" هو mantissa الدقة ، المقياس هو الأسس. في psuedocode: القيمة = UncaledValue 10^(-المقياس)
لا ، لا يوجد تنفيذ حالي في جافا الأساسية أو في مجلس العموم (على الأرجح مكان آخر للعثور عليه) له نفس الوظائف وسهولة الدقة Frexp; ؛ التي أعرفها. إذا كانت موجودة ، فربما تكون في مجموعة أدوات غير مستخدمة على نطاق واسع.