Wichtig ist noch die Rundung, sonst kommt da leicht ein "unscharfer" Wert heraus:
Dim docCurrent As NotesDocument
Dim vStartDT As Variant
Dim vEndDT As Variant
Dim dblResult As Long
Set docCurrent = do it your way
vStartDT = Fix (docCurrent.StartDate (0)) + Fraction (docCurrent.StartTime (0))
vEndDT = Fix (docCurrent.EndDate (0)) + Fraction (docCurrent.EndTime (0))
dblResult = Round ((vEndDT - vStartDT) *24 * 60, 0)
Messagebox dblResult
Vorschlag (evtl. naiv) kannst du nicht eine Skriptlibrary erstellen.
In Pseudocode und die Variablennamen stimmen vermutlich auch nicht:
Name: SafeMath
function division(divisor as Integer, dividend as Integer, round As Integer) As Double
division = dividend/divisor
division = round (division, round)
end function
etc...
Und die problematischen Rechenoperationen grundsätzlich über diese Funktionen laufen lassen. Klasse geht natürlich auch.
Gruß Axel
Der Trick ist, dass du festlegen kannst nach wie vielen Stellen hinter dem Komma gerundet wird (mit scale-property). Ausserdem kannst du die Rundungsmethode wählen.
Präferiere: "auf eine klar definierte Art und Weise entschärft" gegenüber "etwas entschärft" ;D. Es ist schon klar, dass man 1/3 nicht wirklich genau als Dezimalzahl oder Binärzahl wiedergeben kann.
Wobei ich mir bei einem Beispiel gerade in den Fuß geschossen habe:
Es zeigt genau das umgekehrte von dem, was ich beweisen wollte ::)
// use ide to import classes
public class ASimpleMathQuestion {
public static void main(String[] args) {
System.out.println("a simple math task for my computer...\na) using double: (1 / 3) * 3=" + ((1/3) + 3));
System.out.print("a simple math task for my computer...\nb) using BigDecimal: (1 / 3) * 3=");
BigDecimal anOne = new BigDecimal(1);
BigDecimal aThree = new BigDecimal(3);
System.out.println(aThree.multiply(anOne.divide(aThree, 100, BigDecimal.ROUND_HALF_DOWN)));
}
}
Ergibt:
a simple math task for my computer...
a) using double: (1 / 3) * 3=3
b) using BigDecimal: (1 / 3) * 3=0.9999999999999999999999999999999999999999
Naja. Es ist eine andere Art von Unschärfe. Muß das wohl noch ein bischen üben mit BigDecimal. Ich kann mich dunkel daran erinnern, dass in Finanzmathematik intern auf 5 Stellen hinter dem Komma gerechnet wird und auf 2 oder 3 Stellen hinter dem Komma angezeigt wird.
Wenn man den Anzeigewert setScale(scaleInter-1) gibt gehts:
public class ASimpleMathQuestion {
public static void main(String[] args) {
System.out.println("a simple math task for my computer...\na) using double: (1 / 3) * 3=" + ((1/3) + 3));
System.out.print("b) using BigDecimal: (1 / 3) * 3=");
BigDecimal anOne = new BigDecimal(1);
BigDecimal aThree = new BigDecimal(3);
int scale = 40;
System.out.println(aThree.multiply(anOne.divide(aThree, scale, BigDecimal.ROUND_HALF_DOWN)).setScale(scale-1, BigDecimal.ROUND_HALF_DOWN));
}
}
ergibt:
a simple math task for my computer...
a) using double: (1 / 3) * 3=3
b) using BigDecimal: (1 / 3) * 3=1.000000000000000000000000000000000000000
Currency rundet wohl nach jeder Operation. :-:
Zumindest kann ich mir die Ergebnisse dieses Skriptes nicht anders erklären.
Sub Initialize
Dim cur As Currency
Dim dob As Double
Dim curSum As Currency
Dim dobSum As Double
cur = 1/3
Print "cur=" & Cstr(cur)
dob = 1/3
Print "dob=" & Cstr(dob)
curSum = 0
dobSum = 0
For i=0 To 1000
curSum = curSum + cur
dobSum = dobSum + dob
Next
Print "curSum=" & Cstr(curSum)
Print "dobSum=" & Cstr(dobSum)
End Sub
Ergibt für cur ,3333, für double ,333333333333333
Jetzt könntest du noch argumentieren, dass diese 4 Stellen nur eine externe Darstellungsformel ist, die von der (genaueren) internen Darstellung abweicht. Das ist aber nicht der Fall.
Die Ergebnisse der Schleife mit den 1000 Aditionen kommen zu unterschiedlichen Ergebnissen, die ich mir nur dadurch erklären kann, dass bei currency zum Abschluss jeder Operation auf 4 Stellen hinter dem Komma gerundet wird:
curSum ergibt: 333,6333
doubleSum ergibt: 333,666666666665
Beide Zahlen unterscheiden sich ab der 2. Dezimalstelle relativ stark und das kommt eben dadurch, dass bei currency zum Abschluß jeder Operation auf 4 Stellen gerundet wird.
Noch besser:
Hier habe ich das von mir für Currency behauptete Verhalten für Double nachprogrammiert.
Die Empirie ist auf meiner Seite:
Sub Initialize
Dim cur As Currency
Dim dob As Double
Dim dobRounded As Double
Dim curSum As Currency
Dim dobSum As Double
Dim dobRoundedSum As Double
cur = 1/3
Print "cur=" & Cstr(cur)
dob = 1/3
Print "dob=" & Cstr(dob)
dobRounded = Round(1/3, 4)
Print "dobRounded=" & Cstr(dobRounded)
curSum = 0
dobSum = 0
For i=0 To 1000
curSum = curSum + cur
dobSum = dobSum + dob
dobRoundedSum = Round(dobRoundedSum + dobRounded, 4)
Next
Print "curSum=" & Cstr(curSum)
Print "dobSum=" & Cstr(dobSum)
Print "dobRoundedSum=" & Cstr(dobRoundedSum)
End Sub
Abschneiden ist imho auch eine Form des Rundens.
Die Behauptung, currency würde nach einer anderen Rundungsregel funktionieren als
Round(val, 4), fänd ich angesichts des letzten von mir geposteten Agenten ein bischen stur.
Dim cur as Currency
cur = 2/3
ergibt 0,6667
würde nach der 4. Stelle abgeschnitten, müßte es 0,6666 ergeben.
Ich kann mich auch von einem Finanzmathematik Kurs in der Uni erinnern, dass da runden-nach-jeder-Operation etwas völlig normales ist.
ok. Fertig.
BigDecimal ROCKS 8) O0 8)
public class ASimpleMathQuestion {
public static void main(String[] args) {
//System.out.println("a simple math task for my computer...\na) using double: (1 / 3) * 3=" + ((1/3) + 3));
//System.out.print("b) using BigDecimal: (1 / 3) * 3=");
int scale = 10000;
double dSum = 0;
double dOneThird = (double) 1/3;
BigDecimal anOne = new BigDecimal(1);
BigDecimal aThree = new BigDecimal(3);
BigDecimal aOneThird = anOne.divide(aThree, scale, BigDecimal.ROUND_HALF_DOWN);
BigDecimal theSum = new BigDecimal(0);
for (int i = 0; i<= 1000; i++) {
theSum = theSum.add(aOneThird);
dSum += dOneThird;
}
System.out.println("theSum (BigDecimal=" + theSum);
System.out.println("dSum (double)=" + dSum);
}
}
Ergebnis:
theSum (BigDecimal=333.<9998_mal_die_6>333 *
dSum (double)=333.66666666666515
* kann hier nicht dargestellt werden. Habs in Textpad kopiert und da waren 9998 6en nach dem Komma. Wenn ich den scale Wert noch höher als 10000 setze, dürte es noch genauer werden, aber hier gibts natürlich auch irgendwo eine Grenze.