2008-12-09 18 views
12

Estoy considerando escribir dos alternativas de precisión limitadas a BigDecimal, a saber, DecimalInt y DecimalLong. Estos serían capaces de tratar con números dentro de los límites reales de int y long con un número arbitrario de decimales, creables en forma mutable e inmutable. Mi plan es hacer que DecimalInt soporte +/- 999,999,999 a +/- 0,999999999 y DecimalLong igual, pero con hasta 18 dígitos.Clase decimal Java liviana

Esto se realizaría manteniendo un valor de recuento de dígitos decimales de 0-9 para DecimalInt y 0-18 para DecimalLong junto con el valor real almacenado como una escala int o larga. El uso normal sería para números pequeños de decimales, como por ejemplo dinero y precios de acciones, generalmente 2-4 lugares decimales.

Los requisitos esenciales son (a) espacio reducido (2 clases, más OverflowException), y (b) soporte completo de todas las operaciones básicas más todas las matemáticas que tengan sentido.

La búsqueda de resultados en Google no arrojó ningún resultado obvio: todos parecían pertenecer a decimales arbitrarios.

Mis preguntas son: ¿Ya se ha hecho esto? ¿Hay sutilezas ocultas en esto y por eso todavía no se ha hecho? ¿Alguien ha escuchado rumores de que Java sea compatible con un tipo decimal como el de DotNet?

EDITAR: Esto es diferente de BigDecimal porque debería ser (a) mucho más eficiente no tratar con un conjunto de operaciones, y (b) no ajustará BigInteger para que sea más simple en memoria también, y (c) tendrá una opción mutable por lo que será más rápido allí también. En resumen, menos sobrecarga para casos de uso simple como "Quiero almacenar un saldo bancario sin la sobrecarga de BigDecimal y la inexactitud del doble".

EDIT: Tengo la intención de hacer todas las matemáticas usando int o largo para evitar el problema clásico de: 1586,60-708,75 = 877.8499999999999 en lugar de 877,85

+0

"ha sido esto ha hecho?" ¿Qué es diferente acerca de tus clases propuestas y BigDecimal? –

+0

Cuando dice "con un número arbitrario de lugares decimales", ¿quiere decir que tiene un número fijo de decimales en mente o que desea poder admitir cualquier cantidad de lugares decimales? – DJClayworth

+0

Probablemente hubiera sido más rápido escribirlo que tener que tratar con personas que malinterpretan su pregunta aquí. – jmucchiello

Respuesta

0

Si su objetivo es para dispositivos portátiles miran Real. Real permite que el precision del número se establezca de 0 a 16. Está diseñado para teléfonos celulares MIDP.

También es de interés, consulte la biblioteca constructive reals. Aunque no es liviano.

En referencia al comentario a continuación, ¿no puede usar el Apache Commons Math Library para trabajar con fracciones? ¿Hay alguna razón que no funcionará?

+0

Real se ve bien, pero ... está GPL por lo que no puede usarlo comercialmente, y, ¿no es todavía matemática de coma flotante, por lo que sufre problemas con fracciones decimales que no se pueden representar en binario? –

+0

No me di cuenta de que tenía un requisito de licencia. – WolfmanDragon

-1

Me parece que si quiere precisión arbitraria necesitará un número indefinido de bits para representar la mantisa. Eso significa que algún tipo de estrategia de asignación de matriz va a ser necesaria para la mantisa. Puede crear el suyo aquí, pero BigInteger lo hace bastante eficientemente y funciona

Debe especificar cuál es el valor más pequeño (distinto de cero) que necesita representar. Esto será 10^- (2^n), donde n + 1 es el número de bits que asigna al exponente. Con BigDecimal esto es 10^- (2^31). Podría usar un exponente de tamaño arbitrario, pero ese rango debería ser suficiente para cualquiera.

Así que lo que necesita es una mantisa entera sin límites para darle la precisión arbitraria, y un exponente de tamaño fijo, dependiendo de lo que desee que sea su valor mínimo representable. Esencialmente esto es BigDecimal; el único cambio es que usará algún objeto más pequeño en lugar del int utilizado por BigDecimal. Dudo que el ahorro de espacio valga la pena. Creo que BigDecimal hará lo que necesita con apenas más uso de memoria que cualquier solución que usted mismo cree.

Por supuesto, puede elegir un número máximo de cifras significativas que necesitará; entonces necesitas almacenamiento de tamaño fijo para mantisa y exponente, y eso es mucho menos almacenamiento. Solo usa un número fijo de largos como la mantisa.

+0

Por eso mi pregunta decía "precisión limitada", no "precisión arbitraria". –

+0

Y declaró que la precisión de cada uno se limitaría a lo que int y long pueden contener, con un valor separado mantenga el número de decimales. Para eliminar los aros complejos saltó a través de BigInteger. –

+0

Su pregunta dice "con un número arbitrario de lugares decimales". Por favor, decídase. – DJClayworth

0

Si está buscando un número fijo y pequeño de decimales para manejar dinero, esto generalmente se hace manteniendo números enteros (largos si es necesario) de centavos o centésimas de centavo.

Si está tratando con dinero, deberá tener cuidado con la forma en que maneja el redondeo. Si sus cálculos van a ser auditados, hay reglas sobre cómo se hace ese tipo de cosas. También supongo que sabe que algunas operaciones no se pueden llevar a cabo con precisión (la división es el ejemplo obvio).

+0

Precisamente, busco agrupar esa lógica en una clase que tenga en cuenta la escala de su valor y, por lo tanto, puede usarse para operaciones con otros números. –

12

Sospecho que la razón por la cual esto no se ha hecho es que la sobrecarga de BigDecimal y BigInteger no es tan relevante como cree, y evitarlo no vale la pena ni el riesgo de equivocarse de una manera sutil.

Para usar su ejemplo: para cualquier aplicación financiera, guardar unas pocas docenas de bytes es una cuestión de poca importancia y precisión limitada, un factor decisivo (los precios de las acciones suelen ser de 2-4 dígitos en EE. UU., Pero si quiere tratar con los mercados emergentes, encontrará monedas con inflación galopante, donde una suma de 15 dígitos le compra la mitad de una barra de pan).

Básicamente, suena como otro caso de optimización prematura.

+4

¿Alguna vez ha visto un sistema que comercializa productos en una moneda de hiperinflación? Sugeriría que te mantengas alejado de ellos. –

1

La mayoría de las personas que están particularmente preocupadas por los errores de redondeo usan BigDecimal y BigInteger, que funciona lo suficientemente bien en la mayoría de las situaciones.

Sin embargo, en los casos en que el rendimiento es más crítico, usar el doble con redondeo hace el trabajo. Esto a menudo es olvidado por los novatos, pero no se puede simplemente tomar un doble resultado sin una ronda sensible y esperar obtener una respuesta sensata.

En la gran mayoría de los casos, todo lo que necesita es doblar con redondeo.

System.out.printf("%.2f%n", 1586.60-708.75); 

impresiones

877.85