korrekte Integer Wurzel Sqr(Int) abgerundet

Für allgemeine Fragen zur Programmierung mit PureBasic.
SMaag
Beiträge: 184
Registriert: 08.05.2022 12:58

korrekte Integer Wurzel Sqr(Int) abgerundet

Beitrag von SMaag »

Bei der Sqr() Wurzelfunktion in PB, welche über die FPU berechnet wird, bekommt man aufgerundete Ergebnisse, was dann nicht der korrekten Integer Wurzel entspricht, die eigentlich abgerundet sein müsste.

z.b. N = Sqr(7) = 3 => 3*3 =9; die Korrekte Integer Wurzel müsste Sqr(7) = 2 sein.
Vom Standpunkt von PB bei Berechung über die Floating Unit ist das Ergebnis 3 ja ok. Aber die mathematisch korrekte SqrInt() ist das nicht!

Bin da eben drüber gestolpert! Hab das jetzt mit einem Round gelöst
N = Round(Sqr(7), #PB_Round_Down)

Gibt es da eine bessere Lösung für???

Hier mal ein Testcode, der das Problem zeigt

Code: Alles auswählen


EnableExplicit
Define.i N, I
Define.f F

; Methode 1: ab I = 7 bzw I=13 ist N²>I
Debug "aufgerundete Wurzel"
For I = 1 To 49
  N = Sqr(I)
  Debug "I= " + Str(I) + " : Sqr= " + N + " : N*N = " + Str(N*N)
Next

Debug ""
Debug "Korrekte Integer Wurzel"
; Methode 2: korrekte Integer Wurzel N²<=I immer!
For I = 1 To 49
  N = Round(Sqr(I), #PB_Round_Down)
  Debug "I= " + Str(I) + " : Sqr= " + N + " : N*N = " + Str(N*N)
Next


Benutzeravatar
jacdelad
Beiträge: 404
Registriert: 03.02.2021 13:39
Wohnort: Riesa
Kontaktdaten:

Re: korrekte Integer Wurzel Sqr(Int) abgerundet

Beitrag von jacdelad »

Str() wandelt immer in ein integer um bevor ein String frauas gemacht wird. Logisch, dass da aufgerundet wird. Kein Fehler, weder im mathematischen, noch programmiererischen Sinn. Schau dir mal StrF() an. Oder geh den korrekten weg und runde vorher ab, wie von dir beschrieben.
Guten Morgen, das ist ein schöner Tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3 TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: korrekte Integer Wurzel Sqr(Int) abgerundet

Beitrag von STARGÅTE »

Die Funktion Sqr() in PureBasic ist eine Wunzelfunktion für Fließkommazahlen.
Wenn du eine ganze Zahl übergibst und das Ergebnis wieder in eine ganze Zahl speicherst, passieren im Hintergrund zwei Typenumwandlungen, Sqr(7) wird als Sqr(7.0) interpretiert, dann zu 2.646 berechnet und dann auf die ganze Zahl 3 gerundet.

Für ganzzahlige Wurzeln kannst du z.B. das Newton-Verfahren nutzen:
Der Code ist nicht auf Geschwindigkeit optimiert, erfüllt aber sein Zweck.

Code: Alles auswählen

Procedure.q SqrQ(Value.q)
	
	Protected NewResult.q = $7FFFFFFF
	
	If Value < 2
		ProcedureReturn Value
	ElseIf Value < $7FFFFFFF
		NewResult = Value
	EndIf
	
	Repeat
		OldResult = NewResult
		NewResult = (OldResult + Value/OldResult)>>1
	Until NewResult >= OldResult
	
	ProcedureReturn OldResult
	
EndProcedure


Debug SqrQ(7)
Debug SqrQ(99)
Debug SqrQ(123456*123456)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
SMaag
Beiträge: 184
Registriert: 08.05.2022 12:58

Re: korrekte Integer Wurzel Sqr(Int) abgerundet

Beitrag von SMaag »

Sorry war eigentlich blöde Frage! Ist kar, dass das nicht anders geht! Meist ist das auch gar kein Problem.
Sonst müsste man wie STARGATE sagt ein Iterationsverfahren verwenden.

Ich hab dazu auch was bei Rosetta-Code gefunden.
; https://rosettacode.org/wiki/Isqrt_(int ... ot)_of_X#C

Code: Alles auswählen

Procedure.i SqrI(X)
    Protected Q=1 
    Protected T, R
    
    While Q <= X 
      Q << 2 
    Wend
    
    While Q > 1
      Q >> 2  
      T = X -R -Q
      R >> 1
      If T >= 0
        X = T
        R + Q
      EndIf
    Wend
    
    ProcedureReturn R
  EndProcedure

Antworten