Avatar billede nanders Nybegynder
16. februar 2010 - 14:08 Der er 17 kommentarer og
1 løsning

BigDecimal - praktisk brug

Kære Eksperter,

Jeg ønsker at udføre nogle simple regneoperationer på nogle meget små tal (a la 0.0000000000000000007456320237308473), men med meget høj præcision.

Jeg har et program, hvor jeg har en værdi b, fra et kald til en regnemetode.

Jeg ønsker at beregne a=a+b/c med højest mulig nøjagtighed.

a og c er defineret som double. Det er b også

i) hvordan laver jeg dem om til BigDecimal tal?
ii) hvordan udfører jeg regneoperationerne?
iii) b fremkommer ved at jeg kalder en ekstern metode og får returneret svaret, som så lægges i b - skal b også være BigDecimal?

Vh.

nanders

(det er vist noget med at tallene skal laves om til objekter)
Avatar billede arne_v Ekspert
16. februar 2010 - 15:13 #1
BigDecimal har en constructor som tager en double som argument.

Hvis du har mulighed for at bruge den constructor som tager String er det bedre.
Avatar billede arne_v Ekspert
16. februar 2010 - 15:14 #2
Det er naturligvis bedt at lave alle beregninger med alle midlertidige variable som BigDecimal.
Avatar billede nanders Nybegynder
18. februar 2010 - 10:37 #3
Jeg vil meget gerne fortsætte med at bruge double, da en 800-900 variable i min model er erklæret som doubler.

Da jeg ikke er særlig stærk i at implementere constructorer, og nye metoder, ville jeg være meget taknemmelig, om en af jer kunne give et meget simpelt kode eksempel på

a) hvordan jeg erklærer variable
b) hvordan jeg udfører simple regneoperationer med disse.

VH

nanders
Avatar billede arne_v Ekspert
18. februar 2010 - 14:47 #4
BigDecimal syntaxen er ikke koen men simpel nok.

BigDecimal x = new BigDecimal("1.2");
BigDecimal y = new BigDecimal("3.4");
BigDecimal z = new BigDecimal("5.6");
BigDecimal w = x.add(x).multiply(z);
Avatar billede nanders Nybegynder
18. februar 2010 - 16:22 #5
OK,

men hvad nu hvis x,y og z ændrer sig under f.eks. en simulation - så kan det vel ikke være som en streng?
Avatar billede arne_v Ekspert
18. februar 2010 - 16:31 #6
strengen konverteres af constructoren til en intern repraesentation

men BigDecimal objekter er immutable saa du faar hele tiden nye instanser af dem
Avatar billede nanders Nybegynder
25. februar 2010 - 12:38 #7
Mine spm. er:

a) hvad er fejlen med min System.out
b) lægger jeg tallene korrekt sammen, eller skal jeg inde i parantesen for a.add(b) istedet skrive noget andet?

Koden er her:

import java.util.*; //General utilities
import java.io.*; //For the fileoutputstream function.
import java.util.Date; //The date function preventing overwriting issues
import java.text.*; //Used in printing
import java.math.BigDecimal;

public class test
{
BigDecimal a = new BigDecimal ("2");
BigDecimal b = new BigDecimal ("6");
BigDecimal c = new BigDecimal ("13");
BigDecimal d = new BigDecimal ("73");

BigDecimal r = a.add(b);
BigDecimal s = a.add(b).add(c);

double y = 4;
double z = 7;

double x = y+z;

System.out.println(x);
System.out.println(r);

}

VH.

nanders
Avatar billede nanders Nybegynder
25. februar 2010 - 13:36 #8
Undskyld fejlen med System.out

Har fundet ud af det.

Følgende programstump og udskrift illustrerer problemet

Spm. er dog, hvorfor den alm. sammenlægning af x+y nu giver et korrekt resultat?

Har dog haft store problemer med regnefejl på simple regneoperationer.

PROGRAM:

import java.math.BigDecimal;

public class test
{

public void run()
{
BigDecimal a = new BigDecimal ("0.00000000000000000000001111111111111111");
BigDecimal b = new BigDecimal ("0.00000000000000000000002222222222222222");

double x = 0.00000000000000000000001111111111111111;
double y = 0.00000000000000000000002222222222222222;
double z = x+y;

BigDecimal r = a.add(b);
BigDecimal s = a.add(b);

System.out.println("test double x: " + new BigDecimal(x));
System.out.println("test double y: " + new BigDecimal(y));
System.out.println("test1 double x + double y: " + new BigDecimal(x).add(new BigDecimal(y)));
System.out.println("test2 double x + double y: " + (x+y));


System.out.println("test BDa: " + a);
System.out.println("test BDb: " + b);
System.out.println("test a+b '.add()': " + r);
}

}

OUTPUT:

test double x: 1.111111111111111001844422748649926507651390917293669297574544639443938631728769905748777091503143310546875E-23
test double y: 2.22222222222222200368884549729985301530278183458733859514908927888787726345753981149755418300628662109375E-23
test1 double x + double y: 3.333333333333333005533268245949779522954172751881007892723633918331815895186309717246331274509429931640625E-23
test2 double x + double y: 3.333333333333333E-23
test BDa: 1.111111111111111E-23
test BDb: 2.222222222222222E-23
test a+b '.add()': 3.333333333333333E-23


VH.

nanders
Avatar billede arne_v Ekspert
25. februar 2010 - 15:35 #9
Jeg forstaar stadig ikke hvad problemet er.

double skal virke rimeligt indenfor dens usikkerhed

new BigDecimal(doubleval) boer aldrig bruges da den giver saere resultater
Avatar billede nanders Nybegynder
26. februar 2010 - 13:25 #10
Hej Arne,

Problemet opstår når jeg 160 millioner gange skal lægge meget små tal sammen.

Double lader til ikke at være særlig præcis.
Avatar billede nanders Nybegynder
26. februar 2010 - 13:26 #11
Og jeg bruger new BigDecimal("tal")
Avatar billede nanders Nybegynder
26. februar 2010 - 13:39 #12
Hej Arne,

Her er programmet, der illustrerer hvorfor det er problematisk at udføre regneoperationer på doubler:

Resultatet følger efter

import java.math.BigDecimal;

public class test
{

public void run()
{
BigDecimal a = new BigDecimal ("99.99");
BigDecimal b = new BigDecimal ("1.99");
BigDecimal r = a.add(b);

double x = 99.99;
double y = 1.99;
double z = x+y;



System.out.println("test x+y '+': " + z);
System.out.println("test a+b '.add()': " + r);
}

}

Svaret fra prompten:

test x+y '+': 101.97999999999999
test a+b '.add()': 101.98
Avatar billede arne_v Ekspert
27. februar 2010 - 01:49 #13
Det der er også "rimeligt" udfra en floating point betragtning.

Da floating point ikke kan reprænsentere 1/10 elelr 1/100 eksakt, så får man den slags usikkerhed.

Og hvis det ikke er godt nok, så kan man bruge BigDecimal.

Og jeg har stadigvæk ikke forstået hvad dit egentlige problem er.
Avatar billede nanders Nybegynder
01. marts 2010 - 15:59 #14
Hej Arne,

Det er fordi, at jeg 100x i sekundet skal beregne faseovergangs rater for gasser ind i vædsker, vækstrater for bakteriegrupper, omsætning af stoffer, vandbevægelser mv. i et biologisk system, som jeg har lavet en model af i Java.

Det er meget vigtigt, at der ikke overføres hverken mere eller mindre, end det rent faktisk er tilfældet mellem en gas- og vædske fase.

Har læst, at man inden for f.eks. økonomi også bruger BigDecimal.

Jeg tænker blot, om den unøjagtighed der er, som vist ovenfor, bliver større og større, eller om der er en normal fordeling af regnefejlen, så a+b > (korrekt a+b) nogle gange og a+b < (korrekt a+b) andre gange, når man regner a+b ud gentagne gange i det samme edb-program.

Overordnet består mit problem i, at jeg ikke ved nok om de forskellige simple typer (double, float, int) osv. i Java og edb-maskiner generelt.

Ville det f.eks. være bedre hvis min PC var 64 bit og ikke 32 bit. Jeg tænker om 32 vs. 64 bit siger noget om hvorvidt tal skrives og beregnes med 32 stk. 0 og 1 taller når det er 32 bit og 64 stk. 0 og 1 taller når det er 64 bit?

VH.

nanders
Avatar billede arne_v Ekspert
01. marts 2010 - 16:02 #15
Du kan ikke regne med at fejlen konsekvent går i en bestemt retning.

Hvis du skal have mere noejagtighed end double, saa skal du bruge BigDecimal.

Men er di helt sikker på at du har data med mere end 15 betydende cifre??

Det betyder ikke noget funktionelt om din PC er 32 eller 64 bit. Det kan betyde en lille smule med hensyn til performance.
Avatar billede arne_v Ekspert
26. april 2010 - 04:02 #16
Tid at få afsluttet her ?
Avatar billede nanders Nybegynder
26. september 2010 - 12:48 #17
Hej Arne,

Vil du smide et svar her?
Avatar billede arne_v Ekspert
26. september 2010 - 15:17 #18
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester