0

"$([int]($_.length / 1mb)) MB" command converts for example 19099648 to '18 MB', 12054528 to '11 MB'.

Why? How does this rounding work?

Similar differences are reflected in File Explorer's Properties dialog on Windows:

Size: 18.2 MB (19,099,648 bytes)

Size on disk: 18.2 MB (19,099,648 bytes)

How to perform such conversions in VBA?

0

1 Answer 1

4

PowerShell's (invariably case-insensitive) numeric-multiplier suffixes - kb, mb, gb, tb, pb - are binary (base 2) multipliers, i.e. kb corresponds to kibibytes (1024), mb to mebibytes (1024 ^ 2), ... rather than decimal (base 10) multipliers (kilobytes (1000), megabytes (1000 ^ 2), ...) - see Wikipedia for a complete list.

  • This may be surprising, given that abbreviations such as MB nowadays more typically suggest a decimal multiplier (1000 ^ 2) and unambiguous binary abbreviations such as MiB now exist.[1] (And, as you've discovered, File Explorer too uses the binary meaning of KB, MB, ...)

Thus, for instance, 19099648 / 1mb == 19099648 / [Math]::Pow(1024, 2) == 19099648 / 1048576, which evaluates to 18.21484375.

Casting the latter to [int] (which applies half-to-even midpoint rounding[2]) therefore yields 18 (because any fractional part less than .5 is always truncated).

Since you're formatting the number for display yourself, you could use MiB instead of MB to avoid the ambiguity:

"$([int] ($_.Length / 1mb)) MiB"

Alternatively, if you wanted to emulate decimal multipliers, you can take advantage of the fact that PowerShell's number literals also support scientific (exponent-based) notation, so that 1 million (1,000,000) can succinctly be expressed as 1e6 to express the decimal meaning of mega (M):[3]

"$([int] ($_.Length / 1e6)) MB"

As for VBA / VBScript:

Since no multiplier suffixes exist there, you must either spell out the implied numbers (e.g.
CInt(19099648 / 1048576)) or perform the equivalent exponentiation (e.g.
CInt(19099648 / (1024 ^ 2)))


[1] From the linked Wikipedia page (emphasis added): "Systems based on powers of 2, however, might use binary prefixes (kibi, mebi, gibi, ...) and their corresponding symbols (Ki, Mi, Gi, ...) or they might use the prefixes K, M, and G, creating ambiguity when the prefixes M or G are used." The Ki, Mi, Gi , ... units were introduced later, specifically to avoid the ambiguity of K, M, G. Strictly speaking, the initial chars. are all uppercase in both systems, with the exception of lowercase "k", which unambiguously implies the decimal system, if used correctly. For more information, see the binary prefixes Wikipedia article.
However, note that PowerShell is inherently case-insensitive, so that KB is the same as kb. Also, it is unlikely that unambiguously binary suffixes such as KiB will ever be implemented in PowerShell, given that the existing ones cannot neither be removed nor redefined for reasons of backward compatibility.
Finally, note that the inclusion of B, denoting bytes, in PowerShell's suffixes such as MB is somewhat unfortunate, given that they're simply numeric multipliers that can be applied to any number, whether or not it represents bytes. If PowerShell weren't constrained by backward compatibility, K, M, ... could be introduced as decimal multipliers, and Ki, Mi, ... as binary ones.

[2] See this answer for details.

[3] Note that number literals in this format result in [double] (System.Double) numbers, whereas applying the binary suffixes such as mb results in either [int] (System.Int32) or [long] (System.Int64), depending on the size of the resulting number. However, in the context of division (/) PowerShell implicitly outputs a [double] anyway for non-integer results. If needed, you can always cast to a suitable integer type.

Sign up to request clarification or add additional context in comments.

2 Comments

This is weird. So actually 1 MB is not 1 MB in common sense, because in this case MB abbreviation means not megabyte, but mebibyte.
@darekk: Yes, to express it unambiguously it should be "MiB" (base 2), not the ambiguous "MB" (which, according to IEC 80000-13, is unambiguously base 10, but in JEDEC usage from the 1990s it used to be base 2, and the confusion persists). Please see footnote [1] in the answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.