How to overcome 32-bits math limitation of BAT if PS1 workaround alerts HIPS repeatedly?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
DOSadnie
Posts: 155
Joined: 21 Jul 2022 15:12
Location: Coding Kindergarten

How to overcome 32-bits math limitation of BAT if PS1 workaround alerts HIPS repeatedly?

#1 Post by DOSadnie » 19 Jun 2025 08:48

I have a multi-step BAT file that also has a somewhat long fragment which performs selective deletion and reports about that process with details

The problem at hand is reporting of space saved due to removal of those files. That part of my BAT already reports OK after deletion of small files, but in overall its useless due to the CMD intrinsic
Invalid number. Numbers are limited to 32-bits of precision
errors


I have tried out method of inserting PowerShell snippet for keeping track of deleted files, but it evoked a prompt from HIPS of my COMODO for every single file. So I went along with a workaround in form of comparing size of targeted folder before and after deletion- and once again was faced with the limitation of 2,147,483,648 counted bytes, because CMD is [to my surprise] unable to do such big math. Thus I once again went to the method of employing PowerShell for a bidding

I did many tests and unfortunately it all seems to come down to this:


If I will put in my BAT such snippet

Code: Select all

setlocal DisableDelayedExpansion

set "NUMBER_A=100"
set "NUMBER_B=10"

set "TARGET_FILE=%~dp0TEST.txt"

powershell -NoProfile -Command "([int]%NUMBER_A% - [int]%NUMBER_B%) | Out-File -Encoding ASCII -LiteralPath '%TARGET_FILE%'"

echo.
echo Result of %NUM1% - %NUM2% written to file:
type "%TARGET_FILE%"

endlocal
it works OK i.e. after green-lighting it once in my HIPS the PowerShell is able re-write or re-create that TEST.txt file with a "new" difference number of 90 and then paste it in to my still opened CMD window

But if I will adjust any of the two input numbers, e.g. change 100 to 1000, then the HIPS will see this as something new and thus prompt the warning about PowerShell accessing the Registry of Windows


Is there a way to avoid this somehow?

If I had known about all those various issues [like prompts for every single file], I would have written that entire code not as BAT but as PS1. But now I am to just too far gone to simply start from scratch - and I also fear that even using just PowerShell could also lead [again] to similar or even same issues with COMODO

DOSadnie
Posts: 155
Joined: 21 Jul 2022 15:12
Location: Coding Kindergarten

Re: How to overcome 32-bits math limitation of BAT if PS1 workaround alerts HIPS repeatedly?

#2 Post by DOSadnie » 22 Jun 2025 04:06

I thought of using VBS. But since it is deprecated by Microsoft, there is no sense in investing time in using it


But I think I have a valid solution: a workaround using
BAT > AHK > TXT > BAT

I already managed to write test script:

Code: Select all

; AutoHotkey V1 compatible [test] script for [future] subtraction of two large numbers and writing them with conversions to formatted output and right-alignment [which currently uses two sample numbers]

NUMBER_A := 1000000000000000000
NUMBER_B := 200000000000000000
Result_in_bytes := NUMBER_A - NUMBER_B

Temporary_TXT_file := A_ScriptDir . "\TEST.txt"
FileDelete, %Temporary_TXT_file%

; The below calculates values for each unit
KB := Result_in_bytes / 1024
MB := KB / 1024
GB := MB / 1024
TB := GB / 1024
PB := TB / 1024
EB := PB / 1024

; The below formats calculated results to include 2 decimal places
Formatted_to_bytes := Formatted_further_to_include_spaces(Result_in_bytes, false) . " bytes"
Formatted_to_KB := Formatted_further_to_include_spaces(KB) . " KB"
Formatted_to_MB := Formatted_further_to_include_spaces(MB) . " MB"
Formatted_to_GB := Formatted_further_to_include_spaces(GB) . " GB"
Formatted_to_TB := Formatted_further_to_include_spaces(TB) . " TB"
Formatted_to_PB := Formatted_further_to_include_spaces(PB) . " PB"
Formatted_to_EB := Formatted_further_to_include_spaces(EB) . " EB"

; The below calculates maximum length for the purpose of alignment to the right side
Maximum_length_of_a_digit_based_on_the_bytes_number := StrLen(Formatted_to_bytes)

; The below is a helper function for addition of spaces for alignment
Align_to_right(Text_to_align) {
    global Maximum_length_of_a_digit_based_on_the_bytes_number
    Length_of_the_line_being_aligned := StrLen(Text_to_align)
    if (Length_of_the_line_being_aligned >= Maximum_length_of_a_digit_based_on_the_bytes_number)
        return Text_to_align
    Required_space_signs_for_padding := Maximum_length_of_a_digit_based_on_the_bytes_number - Length_of_the_line_being_aligned
    Padding_spaces := ""
    Loop, %Required_space_signs_for_padding%
        Padding_spaces .= " " ; Here is the actual space sign being re-used
    return Padding_spaces . Text_to_align
}

; The below writes to the TXT file
FileAppend, %Formatted_to_bytes%`n, %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_KB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_MB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_GB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_TB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_PB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_EB) "`n", %Temporary_TXT_file%

ExitApp

; The below is a helper function for inserting of a single space sign every 3 digits [from right to left] in the integer part and [with exception of the bytes line] for rounding up fractional parts to 2 decimal places

Formatted_further_to_include_spaces(Number_worked_on, Show_decimal_numbers := true) {
    if (Show_decimal_numbers)
        Number_worked_on := Round(Number_worked_on, 2)
    else
        Number_worked_on := Round(Number_worked_on)

    StringSplit, Parts_split, Number_worked_on, .
    Integer_part := Parts_split1
    Number_with_added_spaces := ""
    while (StrLen(Integer_part) > 3) {
        Number_with_added_spaces := " " . SubStr(Integer_part, -3) . Number_with_added_spaces ; Insert spaces every 3 digits from right to left
        Integer_part := SubStr(Integer_part, 1, StrLen(Integer_part) - 3)
    }
    Number_with_added_spaces := Integer_part . Number_with_added_spaces

    if (Parts_split0 > 1)
        return Number_with_added_spaces . "." . Parts_split2
    else
        return Number_with_added_spaces
}
It works A-OK when run manually from an AHK file - i.e. it creates a TXT file with content

Code: Select all

800 0000 0000 0000 0000 0000 bytes
     781 1250 0000 0000 0000.00 KB
          762 2939 9453 3125.00 MB
               745 5058 8059.69 GB
                    727 7595.76 TB
                         710.54 PB
                           0.69 EB
and it does not alert HIPS. [Previously I had tested reading and pasting content of a one-line TXT file into a CMD window; also without HIPS being waken up]

But now I am having trouble in making my multi-step BAT dump that AutoHotkey code correctly into an AHK file

aGerman
Expert
Posts: 4706
Joined: 22 Jan 2010 18:01
Location: Germany

Re: How to overcome 32-bits math limitation of BAT if PS1 workaround alerts HIPS repeatedly?

#3 Post by aGerman » 22 Jun 2025 06:38

Your uncommon 4-digit grouping works incorrectly. It repeats the last digit of the previous group as first digit in the next group.

*.ps1

Code: Select all

$NUMBER_A = [System.Decimal]1000000000000000000
$NUMBER_B = [System.Decimal]200000000000000000
$Result_in_bytes = $NUMBER_A - $NUMBER_B
$KB = $Result_in_bytes / 1024
$MB = $KB / 1024
$GB = $MB / 1024
$TB = $GB / 1024
$PB = $TB / 1024
$EB = $PB / 1024

$CultureInfo = [System.Globalization.CultureInfo]::CurrentCulture.Clone()
$CultureInfo.NumberFormat.NumberGroupSeparator = " "
$CultureInfo.NumberFormat.NumberGroupSizes = 4
$CultureInfo.NumberFormat.NumberDecimalSeparator = "."

"$([System.String]::Format($CultureInfo, '{0,23:N0}', $Result_in_bytes)) bytes"
"$([System.String]::Format($CultureInfo, '{0,26:N2}', $KB)) KB"
"$([System.String]::Format($CultureInfo, '{0,26:N2}', $MB)) MB"
"$([System.String]::Format($CultureInfo, '{0,26:N2}', $GB)) GB"
"$([System.String]::Format($CultureInfo, '{0,26:N2}', $TB)) TB"
"$([System.String]::Format($CultureInfo, '{0,26:N2}', $PB)) PB"
"$([System.String]::Format($CultureInfo, '{0,26:N2}', $EB)) EB"
pause

Code: Select all

 80 0000 0000 0000 0000 bytes
     781 2500 0000 0000.00 KB
         7629 3945 3125.00 MB
            7 4505 8059.69 GB
                72 7595.76 TB
                    710.54 PB
                      0.69 EB
Press Enter to continue...:
Steffen

DOSadnie
Posts: 155
Joined: 21 Jul 2022 15:12
Location: Coding Kindergarten

Re: How to overcome 32-bits math limitation of BAT if PS1 workaround alerts HIPS repeatedly?

#4 Post by DOSadnie » 25 Jun 2025 07:28

You are right: it was not working correctly- because the sample numbers were to big. I have wrote in some comments about this to the code

As for unusual grouping of numbers [like in a bank account number]: this is what happens if you spend way too many hours on dealing with various snippets- you see the trees but not the forest


Below is a new correct version of the AutoHotkey test code

Code: Select all

/*

AutoHotkey V1-compatible script for subtracting two large numbers [within 16-digit precision limit] and write conversions with formatted output and right-alignment

*/

; The below are two large test numbers within the safe 64-bit precision limit
NUMBER_A := "4000005000001003"
NUMBER_B := "1000000000001002"

; The below performs subtraction
Result_in_bytes := NUMBER_A - NUMBER_B   ; Larger processed numbers will result with incorrect results due to rounding / overflow, because AutoHotkey's internal math uses 64-bit floating point [double], which only supports exact integers up to 15-16 digits [i.e. about 9 quadrillion]

; The below calculates values for each unit
KB := Result_in_bytes / 1024
MB := KB / 1024
GB := MB / 1024
TB := GB / 1024
PB := TB / 1024
EB := PB / 1024

; The below toggles grouping of calculated numbers
Use_formatting_to_groups_for_result_numbers := true   ; Change >>true<< to >>false<< to deactivate the feature of numbers being outputted to TXT file being formatted [with groups separated with spaces]

; The below formats calculated results to include 2 decimal places
Formatted_to_bytes := Formatted_further_to_include_spaces(Result_in_bytes, false) . " bytes"
Formatted_to_KB := Formatted_further_to_include_spaces(KB) . " KB"
Formatted_to_MB := Formatted_further_to_include_spaces(MB) . " MB"
Formatted_to_GB := Formatted_further_to_include_spaces(GB) . " GB"
Formatted_to_TB := Formatted_further_to_include_spaces(TB) . " TB"
Formatted_to_PB := Formatted_further_to_include_spaces(PB) . " PB"
Formatted_to_EB := Formatted_further_to_include_spaces(EB) . " EB"

; The below calculates maximum length for the purpose of alignment to the right side
Maximum_length_of_a_digit_based_on_the_bytes_number := StrLen(Formatted_to_bytes)

; The below is a helper function for addition of spaces for alignment
Align_to_right(Text_to_align) {
    global Maximum_length_of_a_digit_based_on_the_bytes_number
    Length_of_the_line_being_aligned := StrLen(Text_to_align)
    if (Length_of_the_line_being_aligned >= Maximum_length_of_a_digit_based_on_the_bytes_number)
        return Text_to_align
    Required_space_signs_for_padding := Maximum_length_of_a_digit_based_on_the_bytes_number - Length_of_the_line_being_aligned
    Padding_spaces := ""
    Loop, %Required_space_signs_for_padding%
        Padding_spaces .= " "   ; Here is the actual white space sign being re-used
    return Padding_spaces . Text_to_align
}

; The below deletes the TXT file that is to be created later on, if it already exists
Temporary_TXT_file := A_ScriptDir . "\TEST.txt"   ; This defines file location [as the folder from which this AHK file is launched] and its name
if FileExist(Temporary_TXT_file)
{
    FileDelete, %Temporary_TXT_file%
    Sleep, 1111
}

; The below writes results to TXT file
FileAppend, %Formatted_to_bytes%`n, %Temporary_TXT_file%   ; This creates the file
FileAppend, % Align_to_right(Formatted_to_KB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_MB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_GB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_TB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_PB) "`n", %Temporary_TXT_file%
FileAppend, % Align_to_right(Formatted_to_EB), %Temporary_TXT_file%   ; Lack of >>"`n"<< here avoids creation of an extra empty line under the EB line

ExitApp

; The below is a helper function for inserting of a single space sign every 3 digits [from right to left] in the integer part and [with exception of the bytes line] for rounding up fractional parts to 2 decimal places
Formatted_further_to_include_spaces(Number_worked_on, Show_decimal_numbers := true) {
    global Use_formatting_to_groups_for_result_numbers

    if (Show_decimal_numbers)
        Number_worked_on := Round(Number_worked_on, 2)   ; This sets the number of decimal places. Choosing >>0<< will simply turn off showing of them [i.e. TXT will show integers]
    else
        Number_worked_on := Round(Number_worked_on)

    StringSplit, Parts_split, Number_worked_on, .
    Integer_part := Parts_split1

    if (!Use_formatting_to_groups_for_result_numbers) {
        if (Parts_split0 > 1)
            return Integer_part . "." . Parts_split2
        else
            return Integer_part
    }

    Number_with_added_spaces := ""
    StringLen, Length_of_integer_part, Integer_part
    Current_position_in_integer_part := Length_of_integer_part

    while (Current_position_in_integer_part > 3) {
        Number_with_added_spaces := " " . SubStr(Integer_part, Current_position_in_integer_part - 2, 3) . Number_with_added_spaces
        Current_position_in_integer_part -= 3
    }
    Number_with_added_spaces := SubStr(Integer_part, 1, Current_position_in_integer_part) . Number_with_added_spaces

    if (Parts_split0 > 1)
        return Number_with_added_spaces . "." . Parts_split2
    else
        return Number_with_added_spaces
}

/*

To manually check calculations outputted to the TXT file use services like:

https://thistothatcalculator.com/bytes-to-tb-calculator/
https://unitconverters.net/data-storage-converter.html
https://whatsabyte.com/P1/byteconverter.htm

*/
and its batch version

Code: Select all

@echo off

> "TEST.ahk" (
    echo /*
    echo.
    echo AutoHotkey V1-compatible script for subtracting two large numbers [within 16-digit precision limit] and write conversions with formatted output and right-alignment
    echo.
    echo */
    echo.
    echo ; The below are two large test numbers within the safe 64-bit precision limit
    echo NUMBER_A := "4000005000001003"
    echo NUMBER_B := "1000000000001002"
    echo.
    echo ; The below performs subtraction
    echo Result_in_bytes := NUMBER_A - NUMBER_B   ; Larger processed numbers will result with incorrect results due to rounding / overflow, because AutoHotkey's internal math uses 64-bit floating point [double], which only supports exact integers up to 15-16 digits [i.e. about 9 quadrillion]
    echo.
    echo ; The below calculates values for each unit
    echo KB := Result_in_bytes / 1024
    echo MB := KB / 1024
    echo GB := MB / 1024
    echo TB := GB / 1024
    echo PB := TB / 1024
    echo EB := PB / 1024
    echo.
    echo ; The below toggles grouping of calculated numbers
    echo Use_formatting_to_groups_for_result_numbers := true   ; Change ^>^>true^<^< to ^>^>false^<^< to deactivate the feature of numbers being outputted to TXT file being formatted [with groups separated with spaces]
    echo.
    echo ; The below formats calculated results to include 2 decimal places
    echo Formatted_to_bytes := Formatted_further_to_include_spaces^(Result_in_bytes, false^) . " bytes"
    echo Formatted_to_KB := Formatted_further_to_include_spaces^(KB^) . " KB"
    echo Formatted_to_MB := Formatted_further_to_include_spaces^(MB^) . " MB"
    echo Formatted_to_GB := Formatted_further_to_include_spaces^(GB^) . " GB"
    echo Formatted_to_TB := Formatted_further_to_include_spaces^(TB^) . " TB"
    echo Formatted_to_PB := Formatted_further_to_include_spaces^(PB^) . " PB"
    echo Formatted_to_EB := Formatted_further_to_include_spaces^(EB^) . " EB"
    echo.
    echo ; The below calculates maximum length for the purpose of alignment to the right side
    echo Maximum_length_of_a_digit_based_on_the_bytes_number := StrLen^(Formatted_to_bytes^)
    echo.
    echo ; The below is a helper function for addition of spaces for alignment
    echo Align_to_right^(Text_to_align^) {
    echo     global Maximum_length_of_a_digit_based_on_the_bytes_number
    echo     Length_of_the_line_being_aligned := StrLen^(Text_to_align^)
    echo     if ^(Length_of_the_line_being_aligned ^>= Maximum_length_of_a_digit_based_on_the_bytes_number^)
    echo         return Text_to_align
    echo     Required_space_signs_for_padding := Maximum_length_of_a_digit_based_on_the_bytes_number - Length_of_the_line_being_aligned
    echo     Padding_spaces := ""
    echo     Loop, %%Required_space_signs_for_padding%%
    echo         Padding_spaces .= " "   ; Here is the actual white space sign being re-used
    echo     return Padding_spaces . Text_to_align
    echo }
    echo.
    echo ; The below deletes the TXT file that is to be created later on, if it already exists
    echo Temporary_TXT_file := A_ScriptDir . "\TEST.txt"   ; This defines file location [as the folder from which this AHK file is launched] and its name
    echo if FileExist^(Temporary_TXT_file^)
    echo {
    echo     FileDelete, %%Temporary_TXT_file%%
    echo     Sleep, 1111
    echo }
    echo.
    echo ; The below writes results to TXT file
    echo FileAppend, %%Formatted_to_bytes%%`n, %%Temporary_TXT_file%%   ; This creates the file
    echo FileAppend, %% Align_to_right^(Formatted_to_KB^) "`n", %%Temporary_TXT_file%%
    echo FileAppend, %% Align_to_right^(Formatted_to_MB^) "`n", %%Temporary_TXT_file%%
    echo FileAppend, %% Align_to_right^(Formatted_to_GB^) "`n", %%Temporary_TXT_file%%
    echo FileAppend, %% Align_to_right^(Formatted_to_TB^) "`n", %%Temporary_TXT_file%%
    echo FileAppend, %% Align_to_right^(Formatted_to_PB^) "`n", %%Temporary_TXT_file%%
    echo FileAppend, %% Align_to_right^(Formatted_to_EB^), %%Temporary_TXT_file%%   ; Lack of ^>^>"`n"^<^< here avoids creation of an extra empty line under the EB line
    echo.
    echo ExitApp
    echo.
    echo ; The below is a helper function for inserting of a single space sign every 3 digits [from right to left] in the integer part and [with exception of the bytes line] for rounding up fractional parts to 2 decimal places
    echo Formatted_further_to_include_spaces^(Number_worked_on, Show_decimal_numbers := true^) {
    echo     global Use_formatting_to_groups_for_result_numbers
    echo.
    echo     if ^(Show_decimal_numbers^)
    echo         Number_worked_on := Round^(Number_worked_on, 2^)   ; This sets the number of decimal places. Choosing ^>^>0^<^< will simply turn off showing of them [i.e. TXT will show integers]
    echo     else
    echo         Number_worked_on := Round^(Number_worked_on^)
    echo.
    echo     StringSplit, Parts_split, Number_worked_on, .
    echo     Integer_part := Parts_split1
    echo.
    echo     if ^(!Use_formatting_to_groups_for_result_numbers^) {
    echo         if ^(Parts_split0 ^> 1^)
    echo             return Integer_part . "." . Parts_split2
    echo         else
    echo             return Integer_part
    echo     }
    echo.
    echo     Number_with_added_spaces := ""
    echo     StringLen, Length_of_integer_part, Integer_part
    echo     Current_position_in_integer_part := Length_of_integer_part
    echo.
    echo     while ^(Current_position_in_integer_part ^> 3^) {
    echo         Number_with_added_spaces := " " . SubStr^(Integer_part, Current_position_in_integer_part - 2, 3^) . Number_with_added_spaces
    echo         Current_position_in_integer_part -= 3
    echo     }
    echo     Number_with_added_spaces := SubStr^(Integer_part, 1, Current_position_in_integer_part^) . Number_with_added_spaces
    echo.
    echo     if ^(Parts_split0 ^> 1^)
    echo         return Number_with_added_spaces . "." . Parts_split2
    echo     else
    echo         return Number_with_added_spaces
    echo }
    echo.
    echo /*
    echo.
    echo To manually check calculations outputted to the TXT file use services like:
    echo.
    echo https://thistothatcalculator.com/bytes-to-tb-calculator/
    echo https://unitconverters.net/data-storage-converter.html
    echo https://whatsabyte.com/P1/byteconverter.htm
    echo.
    echo */
)

pause
which produces the very same AHK file - with exception of adding to it one extra empty line at its very end [that I have no idea where its coming from and have failed at removing it]


The AHK when run produces such text

Code: Select all

3 000 005 000 000 001 bytes
    2 929 692 382 812.50 KB
        2 861 027 717.59 MB
            2 793 972.38 GB
                2 728.49 TB
                    2.66 PB
                    0.00 EB

Post Reply