"Space required" rounding
It seems that NSIS actually truncates extra digits of the value. For example, if all files require 1.59 MB of disk space, NSIS displays "Space required: 1.5MB".
24 posts
__The problem is that a free space needs to be rounded down and, therefore, this function must have two versions or additional parameter:
static void NSISCALL SetSizeText(int dlgItem, int prefix, unsigned kb)
{
char scalestr[32], byte[32];
unsigned sh=0;
int scale=LANG_KILO;
if (kb >= 1024*1024) { sh=20; scale=LANG_GIGA; kb+=(1<<20)/10; }
else if (kb >= 1024) { sh=10; scale=LANG_MEGA; kb+=(1<<10)/10; }
wsprintf(
GetNSISString(g_tmp,prefix)+mystrlen(g_tmp),
"%u.%u%s%s",
kb>>sh,
((kb*10)>>sh)%10,
GetNSISString(scalestr,scale),
GetNSISString(byte,LANG_BYTE)
);
my_SetDialogItemText(m_curwnd,dlgItem,g_tmp);
}
__If you don't want to increase size of exehead, please at least increase number of digits after the decimal point: replace "((kb*10)>>sh)%10" with "((kb*100)>>sh)%100". BTW, this construction in its current state fails with sizes>409.5GB (with two digits after point it fails after 40.95GB), so consider using a 64-bit number:
static void NSISCALL SetSizeText(int dlgItem, int prefix, unsigned kb, bool RoundUp)
{
char scalestr[32], byte[32];
unsigned sh=0;
int scale=LANG_KILO;
if (kb >= 1024*1024) { sh=20; scale=LANG_GIGA; }
else if (kb >= 1024) { sh=10; scale=LANG_MEGA; }
if (RoundUp) { kb+=(1<<sh)/10; }
wsprintf(
GetNSISString(g_tmp,prefix)+mystrlen(g_tmp),
"%u.%u%s%s",
kb>>sh,
((kb*10)>>sh)%10,
GetNSISString(scalestr,scale),
GetNSISString(byte,LANG_BYTE)
);
my_SetDialogItemText(m_curwnd,dlgItem,g_tmp);
}
(UINT)((((UINT64)kb*100)>>sh)%100)
if (kb >= 1024) { sh=10; scale=LANG_MEGA; }
if (kb >= 1024*1024) { sh=20; scale=LANG_GIGA; }
BTW, this construction in its current state fails with sizes>409.5GB (with two digits after point it fails after 40.95GB)Actually, it's limited at 4TB, because it's counted in kilobytes, not bytes.
Actually, it's limited at 4TB, because it's counted in kilobytes, not bytes.It is multilplied by 10 and then divided back, so limit is 409.5GB.
I'm having second thoughts about the rounding up. It doesn't make any sense to round up just the required size and round down the available size. It causes a weird situation where if the available and required sizes are the same, they may not be displayed as such. Even more, the required size displays as bigger than the available size, yet the installation is allowed because they're equal. They should both be rounded using the same method. Why do you think the available size should be rounded down?(((kb & 0x00FFFFFF) * 10) >> sh) % 10, // 0x00FFFFFF mask is used to
// prevent overflow that causes
// bad results
As for rounding direction... Overestimate of available space is dangerous as well as underestimate of required space 😉
unsigned fraction;
//---
__asm
{
mov eax,kb
mov ebx,10
mov ecx,sh
mul ebx
shrd eax,edx,cl
shr edx,cl
div ebx
mov fraction,edx
}
orkb+=(1<<(sh-1))/10;
I think the second variant is more rational.kb+=(1<<sh)/20;
P.S. Should not we display two digits after the point while using rounding to nearest?
static void NSISCALL SetSizeText(int dlgItem, int prefix, unsigned kb)
{
char scalestr[32], byte[32];
unsigned sh=0;
unsigned fraction;
int scale=LANG_KILO;
if (kb >= 1024) { sh=10; scale=LANG_MEGA; }
if (kb >= 1024*1024) { sh=20; scale=LANG_GIGA; }
kb+=(1<<sh)/20;
__asm
{
mov eax,kb
mov ebx,10
mov ecx,sh
mul ebx
shrd eax,edx,cl
shr edx,cl
div ebx
mov fraction,edx
}
wsprintf(
GetNSISString(g_tmp,prefix)+mystrlen(g_tmp),
"%u.%u%s%s",
kb>>sh,fraction,
GetNSISString(scalestr,scale),
GetNSISString(byte,LANG_BYTE)
);
my_SetDialogItemText(m_curwnd,dlgItem,g_tmp);
}
no mask tricks this time to reduce the sizeWhat did you mean? The 0x00FFFFFF mask is still there.