evinben
Goto Top

Mit IF-Befehl Dezimalzahlen richtig vergleichen.

Zahlen wie
8.3
13.7
25.6
usw. werden nicht wie erwartet behandelt.

Hallo,

mir gelingt mit IF leider nicht zwei Zahlen mit Dezimaltrennzeichen richtig miteinander zu vergleichen. Z. B. eine Zahl wie 26.5 wird nicht wie erwartet ausgewertet.
(Bzw. die gleiche Zahl mit Komma 26,5 je nachdem. In dem von mir eingesetzten System akzeptiert IF nur Punkt als Dezimaltrennzeichen, ansonsten Syntaxfehler. Die Kleinigkeit ist nur am Rande erwähnt, da ja jedes Zeichen nach der Eingabe in ein beliebiges Zeichen geändert werden kann.)

In dem Code-Beispiel unten soll bis 30 ab der eingegebenen Zahl gezählt werden. Es funktioniert, solange keine Dezimalzahl eingegeben wird. Bei Eingabe von 26.5 wird das Ergebnis wie folgt fehlerhaft ausgegeben:

back-to-topFehlerhafte Ausgabe

3
4
5
6
7
8
9
27
28
29
30

Das Ergebnis soll bei einem Schritt von 1 jedoch so sein:

back-to-topErwartete Ausgabe

27
28
29
30

Sicherlich gäbe es hierfür leichte Lösungen, nur ich komme leider nicht mehr alleine weiter.

back-to-topCode-Beispiel

@echo off
@prompt -$G
chcp 1252 >nul

:M1
echo.
set /p "InputNumber=Geben Sie eine Zahl, ab der bis 30 gezählt werden soll: "  

setlocal enabledelayedexpansion
set Count=

:Zähler bis 30 mit einem Inkrement-Wert 1 setzen
for /l %%d in (1,1,30) do (
	rem Nachfolgend die Vergleichsvariablen unbedingt ohne Anführungszeichen belassen, damit der Vergleich der beiden Zahlen 
	rem in deren gewöhnlichen normalen Steigung erfolgen kann (ansonsten wird z. B. 2 größer als eine Zahl zw. 10 und 20 ausgewertet usw.).
	if %%d GTR %InputNumber% echo %%d
	)

:Erneute Eingabe
goto :M1

:pause >nul

Gruß
evinben

Content-ID: 196778

Url: https://administrator.de/contentid/196778

Ausgedruckt am: 24.11.2024 um 12:11 Uhr

rubberman
rubberman 10.01.2013 aktualisiert um 19:52:11 Uhr
Goto Top
Hallo evinben.

Batch kennt keine Dezimalzahlen. Somit gilt für Dezimalzahlen: es sind einfache Strings, die Zeichenweise von links nach rechts verglichen werden. Also nicht "fehlerhaft", sonder wie für einen String erwartet face-wink

Workaround könnte sein, den String an Punkt (oder Komma) zu trennen, die linke Seite mit vorangestellten Nullen und die rechte Seite mit nachgestellten Nullen jeweils auf eine fixe Stringlänge erweitern. Beide Strings neu kombinieren.
Das gleiche mit dem 2. Vergleichsoperand tun und vergleichen. Wie lang "fix" ist, hängt von der Maximalgröße bzw. der maximalen Anzahl Nachkommastellen ab.
Diese Info bist du noch schuldig face-wink

Grüße
rubberman
pieh-ejdsch
pieh-ejdsch 12.01.2013 aktualisiert um 14:30:51 Uhr
Goto Top
moin evinben,

es genügt auch die Werte Ohne Vornull in die For /l Schleife dreimal hineinzulegen.
Ausgabe ist dann die Ganzzahl, weil der erste Wert immer ausgegeben wird (es sei denn der Endwert ist kleiner).
Eine zweite Ausgabe erfolgt nicht, ist ja auch der Anfangswert.
Ebenso interessiert die Schrittweite nicht:
 rem mit DezimalKomma
set "Zahl=25,3"  
for /l %%i in (%zahl% %zahl% %zahl%) do echo %%i
 rem oder auch mit DezimalPunkt
set "Zahl=25.3"  
for /l %%i in (%zahl% %zahl% %zahl%) do echo %%i

 rem nur beim Punkt als Dezimaltrenner geht es gleich so:
for /l %%i in (23.4:5 1-3 30,6+4) do echo %%i

 rem sonst eben mit zwei for /L
set "Zahl=13,73"  
for /l %%i in (%zahl% %zahl% %zahl%) do for /l %%I (%%i 1 30) do echo %%I

Die genauere Ausgabe ab der aufgerundeten Zahl wäre dann über Separierung von Komma und Punkt:
> for /f "tokens=1,2delims=,." %i in ("25,001") do @for /l %a in (1 1 30) do @if %a gtr %i (echo %a) else if %a equ %i if %j equ 0 echo %a

Gruß Phil
evinben
evinben 12.01.2013 um 22:39:56 Uhr
Goto Top
Hallo,

was sagt ihr dazu? Ziemlich dick geworden! Wie kompakter?
Verbesserungsvorschläge wie immer wilkommen.

@goto :EndOfComent
:~~~~~~~~~~~~~~~~~

Batch kennt keine Dezimalzahlen. Daher ist es notwendig vor dem Vergleich die Dezimaltrennzeichen (wie "," bzw. "." u. s.) zu entfernen.  
Unterscheiden sich die beiden Zahlen in der Anzahl der Nachkommastellen, dann muss diejenige Zahl, die weniger Nachkommastellen als die andere hat, 
am Ende mit Nullen ausgeglichen werden.  
Soll z. B. eine Zahl wie 27,878 mit einer Zahl wie 13,2 verglichen werden, dann müssen die beiden Zahlen wie folgt angepasst werden:
1. Zahl: 27878
2. Zahl: 13200

Mit dem IF-Befehl können die beiden Zahlen z. B. so verglichen werden:

IF 27878 GTR 13200 (
	echo Die 1. Zahl ist größer und es geht weiter & goto :weiter
	) else (echo Die 1. Zahl ist kleiner. Vorgang wird abgebrochen.)
:Weiter

Bekannte Beschränkungen:
IF-Befehl kann mit dem Vergleichsoperator GTR (größer als) max. 9 stellige Zahlen vergleichen. 

:EndOfComent
:~~~~~~~~~~~
 

@echo off
@prompt -$G
chcp 1252 >nul

:Eingabe
echo.
set InputNumber=
set /p "InputNumber=Geben Sie eine Zahl, ab der bis 30 gezählt werden soll (Dezimalzahlen werden unterstützt): " ||(  
	echo Geben Sie mindestens eine Zahl ein.
	goto :Eingabe
	)

:Eventuell vorhandene Dezimaltrennzeichen filtern:
set "InputNumber=%InputNumber:,=/%"  
set "InputNumber=%InputNumber:.=/%"  

set "Tokens=*"  

:ZahlPrüfung
:Die Anzahl der Ziffern und in der zweiten Runde die Anzahl eventueller Dezimalstellen ermitteln:
set String=
for /f "tokens=%Tokens% delims=/" %%d in ('echo %InputNumber%') do (  
	set String=%%d
	)

:Aktion nach der zweiten Runde
if "%Tokens%"=="2" (  
	set "InputNumber=%InputNumber:/=%"  
	rem Wenn keine Nachkommastellen vorhanden sind, dann direkt weiter
	if not defined String (set StrLength= &goto :Zählen)
	)

set StrLength=
setlocal enabledelayedexpansion
call :ZeichenZähler

if %StrLength% GTR 9 (echo Es können nur Zahlen bestehend aus max. 9 Ziffern verglichen werden. &goto :Eingabe)
:In der zweiten Runde die Anzahl der Nachkommastellen ermitteln.
if %Tokens% NEQ 2 (set Tokens=2&goto :ZahlPrüfung)

:echo Anzahl der Zeichen: %StrLength%
goto :Zählen

:ZeichenZähler
if defined String if not "!String:~%StrLength%,1!"=="" (  
set /a StrLength+=1
goto :ZeichenZähler
)
goto :eof

:Zählen

:Eventuelle Nachkommastellen in Nullen umwandeln:
set Nullen=
for /l %%d in (1,1,%StrLength%) do set Nullen=0!Nullen!

:Zähler bis 30 mit einem Inkrement-Wert 1 setzen
set Count=
for /l %%d in (1,1,30) do (
	rem Nachfolgend die Vergleichsvariablen unbedingt ohne Anführungszeichen belassen, damit der Vergleich der beiden Zahlen 
	rem in deren gewöhnlichen normalen Steigung erfolgen kann (ansonsten wird z. B. 2 größer als eine Zahl zw. 10 und 20 ausgewertet usw.).
	if %%d%Nullen% GTR %InputNumber% echo %%d
	)
endlocal
goto :Eingabe


timeout /t 3 >nul
:pause >nul

Gruß
evinben
rubberman
rubberman 12.01.2013 um 23:37:56 Uhr
Goto Top
Hallo evinben,

wie schon angemerkt, kannst du getrost als Zeichenfolge vergleichen. Somit umschiffst du auch das numerische Limit.
@echo off &setlocal
set /a padding=5

set "inp="  
set /p "inp=Input: "  

for /f "tokens=1* delims=.," %%i in ("%inp%") do (  
  call :fix op1 %padding% %%i %%j
)

setlocal EnableDelayedExpansion
for /l %%d in (1,1,30) do (
  call :fix op2 %padding% %%d
  echo ^> if "!op2!" gtr "!op1!" echo d  
  if "!op2!" gtr "!op1!" echo %%d  
  echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
)
endlocal

pause
goto :eof


:fix  refOutVarName padSize intPart [floatPart]
setlocal EnableDelayedExpansion
set "pad="  
for /l %%i in (1 1 %~2) do set "pad=!pad!0"  
set "s1=%pad%%~3"  
set "s2=%~4%pad%"  
set "s=!s1:~-%~2!.!s2:~,%~2!  
endlocal &set "%~1=%s%"  
goto :eof
Wenn du padding auf 50 statt 5 setzt, kann deine eingegebene Zahl bis zu 50 Vor- und 50 Nachkommastellen haben.

Grüße
rubberman
pieh-ejdsch
pieh-ejdsch 13.01.2013 aktualisiert um 16:13:21 Uhr
Goto Top
moin,

die Forschleife mit 'echo %InputNumber%' sieht etwas verkompliziert aus.
Wenn die Vergleiche als Zeichenfolge gemacht werden reicht die Vornull aus, Hinter dem DeziMal können auch die letzten Nullen entfernt werden (statt hinzugefügt).

Beim Überprüfen auf Fehler mit Rücksprung zum setzen der Variable, muss nicht unbedingt eine leere Variable erstellt werden. Nur wenn die Prüfung nicht eingebaut ist.

@echo off
setlocal enabledelayedexpansion

:Input
set /p "Input=Zahl eingeben: "||echo Fehler.&& goto :Input  
set "Input=%Input:,=.%"  

for /f "tokens=*delims=+0" %%A in ("+%Input%.") do (set /a "A=%%~nA",N=A  
  set "D=%%~xA"  
  if defined D for %%Z in ("!D:0=.!") do set "Z=%%~nxZ" &if %%~nxZ neq !! set "Z=!Z:.=0!" &set "Z=,!Z:~1!" &set /a "N=A+1"  
)
if not defined N goto :Input
echo Eingabe gekuerzt: !A!!Z!
echo(
for /l %%d in (%N% 1 30) do echo %%d
pause
exit /b

Gruß Phil
rubberman
rubberman 13.01.2013 um 03:45:21 Uhr
Goto Top
Hallo Phil.

Hinter dem DeziMal können auch die letzten Nullen entfernt werden (statt hinzugefügt).

Guter Einwand. Das vereinfacht die Sache zwar nicht, man muss sich aber andererseits keine Sorgen über die Anzahl der Nachkommastellen machen.

Grüße
rubberman