Seite 1 von 2

SQL Funktion Round in PB umwandeln

Verfasst: 07.03.2009 17:34
von TheSaint
Hallo Zusammen,

leider krieg ich es irgendwie nicht hin, dieseFunktion, die ich in einem Access Modul nutze, in PB umzuwandeln:

Code: Alles auswählen

Function fctRound(varNr As Variant, Optional varPl As Integer = 2) As Double

'by Konrad Marfurt + ("" by) Luke Chung + Karl Donaubauer
'raus hier bei nicht-nummerischem Argument
    
If Not IsNumeric(varNr) Then Exit Function
        
  fctRound = Fix("" & varNr * (10 ^ varPl) + Sgn(varNr) * 0.5) / (10 ^ varPl)

End Function
Wäre toll, wenn jemand mal draufschauen könnte und mir Hilfestellung geben könnte.
Habe schon nachgesehen nach dem PB - Befehl Round. Aber der ist zu ungenau.

Schon mal vielen Dank für Eure Hilfe.

Verfasst: 07.03.2009 17:51
von Kaeru Gaman
nuja... da das so eine sache ist, welche Funktion intern floats verwendet und welche für doubles geeignet ist,
ist mir das jetzt zu aufwendig dafür ne procedure zu schreiben die nachher doch nicht "genau genug" ist...

hast du das schon mal probiert, das über den umweg eines strings zu machen?
also erst StrD mit dementsprechend Nachkommastellen, und dann ValD?

Verfasst: 07.03.2009 18:56
von TheSaint
Hallo Kaeru Gaman,

vielen Dank für Deine Antwort.
Kaeru Gaman hat geschrieben:hast du das schon mal probiert, das über den umweg eines strings zu machen?
also erst StrD mit dementsprechend Nachkommastellen, und dann ValD?
Ja, habe ich versucht. Habe es aber wieder verworfen.
War zu ungenau. Deshalb dachte ich ja, das man die o. g.
Funktion in PB übersetzen könnte. Doch krieg ich das nicht hin.

Verfasst: 07.03.2009 19:23
von Kaeru Gaman
nunja....
kann man natürlich, allerdings arbeitet Pow() soweit ich weiß mit Float,
da wird man also niemals die genauigkeit von Double erreichen können.

davon ab... "War zu ungenau" ist halt eine recht abenteuerlich ungenaue aussage.

wo hat es denn geklemmt?

ehrlich gesagt halte ich eine lösung über ValD() und StrD() für das genaueste, was mit Standardtypen möglich ist.

ob du mit einer Übersetzung deiner Funktion überhaupt diese genauigkeit erreichst, ist noch die Frage.

außerdem... worauf stützt du denn deine Aussage "ist ungenau"?
... auf die Rückgabewerte irgendwelcher anderer Funktionen in VB oder SQL?
woher willst du denn wissen, dass diese Funktionen "genauer" sind?
du kannst doch nur sehen, dass sie ein anderes Ergebnis liefern....

und "absolute genauigkeit" ist mit Fließkommazahlen sowieso unmöglich,
und selbst mit spezial-libs oder sogar theoretisch nur in der Menge der Rationalen Zahlen möglich.

Verfasst: 07.03.2009 20:40
von TheSaint
Hallo Kaeru Gaman,

vielen Dank für Deine Antwort.
Kaeru Gaman hat geschrieben:und "absolute genauigkeit" ist mit Fließkommazahlen sowieso unmöglich,
und selbst mit spezial-libs oder sogar theoretisch nur in der Menge der Rationalen Zahlen möglich.
Ich werde es noch mal versuchen. Vielen Dank.

Verfasst: 08.03.2009 14:24
von mk-soft
Mal Übersetzt

Code: Alles auswählen

Procedure.d SgnD(value.d)
  If value < 0.0
    ProcedureReturn -1.0
  ElseIf value > 0.0
    ProcedureReturn 1.0
  Else
    ProcedureReturn 0.0
  EndIf
EndProcedure

Procedure.d fctRound(varNr.d, varPl.i = 2)

  ;by Konrad Marfurt + ("" by) Luke Chung + Karl Donaubauer + to PB by mk-soft
  Protected result.d
  result = Round(varNr * Pow(10.0,varPl) + Sgnd(varNr) * 0.5, #PB_Round_Down) / Pow(10.0,varPl)
  ProcedureReturn result
  
EndProcedure

Debug fctRound(12.345678123456734567)
FF :wink:

Verfasst: 08.03.2009 15:17
von Kaeru Gaman
wenn du schon Round einbaust, kannst du auch RoundNearest benutzen, und auf SgnD verzichten.

der Gäg sollte ja sein, auf Round zu verzichten.

also, wenn du eh zweimal Pow() drin hast und SgnD erstellt hast,
kannst du auch IntQ() zum beschneiten benutzen...

.... und wie gehabt, wenn Pow() nur mit Float arbeitet, ist das alles für die Füße.


... aber Monseur wollte ja nicht auf weiterführende Fragen antworten,
konnte nicht mal zum Ausdruck bringen, was er mit "ungenau" meint.
die Wahrscheinlichkeit ist hoch, dass es am IEEE 754 selber liegt.

Verfasst: 08.03.2009 15:27
von mk-soft
Jup,

Ich weis auch das es einfacher geht. Pow braucht man ja nur um auf die nachkommastellen zu kommen. Da reicht ein Float.

wenn man das ganze auch Float umsetzt schmeist der Debugger (Wohl Intern alles auf Double) einen ungenauen Wert raus.

Code: Alles auswählen

Procedure.d fctRound2(varNr.d, varPl.i = 2)

  ;by Konrad Marfurt + ("" by) Luke Chung + Karl Donaubauer + to PB by mk-soft
  Protected result.d
  result = Round(varNr * Pow(10.0,varPl), #PB_Round_Nearest) / Pow(10.0,varPl)
  ProcedureReturn result
  
EndProcedure

Verfasst: 08.03.2009 15:34
von Kaeru Gaman
> Pow braucht man ja nur um auf die nachkommastellen zu kommen. Da reicht ein Float

hu?

Pow wird hier benutzt, um eine Zahl erst zu vergrößern und dann wieder zu verkleinern.
das macht die Ganze sache, die bei 32bit Float schon ungenau genug ist, noch ungenauer.
da wäre es schon wünschenswert, durchgehend mit Double arbeiten zu können.


die beste lösung wäre ein direktes FPU-Kommando.
wäre chique wenn es so eins gäbe...

Verfasst: 08.03.2009 15:54
von mk-soft
Intern immer mit Double Rechnen. Sehe da kein Problem für die meisten Anwendungen. Pow(...) rechnet auch mit Double
Alles was daüber liegt reicht eine FPU auch nicht mehr und muss über APM Routinen berechnet werden.