Короткий формат размера

Sep 22, 2007 18:41

Многие наверно знакомы с курьезом, связанным с трактованием широкораспространенных приставок системы СИ, примененных к единицам информации. Сколько байт в мегабайте? А сколько килобайт? Не смотря на несоответствие десятичных и двоичных величин (103 и 210, 106 и 220, etc), все твердо помнят, что в килограмме 1024 грамма, а в килобайте 1000 байт. Между тем, производители жестких дисков (а также CD/DVD болванок и дискет) неплохо на этом выигрывают.
   Продавая винчерстер на 80 ГБ, производитель не упоминает, что под гигабайтом подразумевается 109, а не 230 байт (впрочем, видимо, по технологическим причинам (а может, чтобы не сильно наглеть) объем винчестера оказывается 74,5 ГБ, но все-таки никак не заявленные 80 ГБ). Не помогут в борьбе с этим жульничеством и специальные двоичные величины для единиц информации, такие как кибибайт (KiB), мебибайт (MiB), гибибайт (GiB), так как появились они совсем недавно, неблагозвучно звучат и не способны преодолеть инерцию общественного мышления. Появилась даже градация мегабайта на длинный (1 048 576 байт), средний (1 024 000 байт) и короткий (1 000 000 байт). «Короткий» мегабайт иногда называют «коммерческим» мегабайтом. Подробнее читайте в википедии.
   Но речь в этом посте пойдет о том, как получить короткую запись единиц информации (не путать с «коротким» мегабайтом), используемую, например, в проводнике Windows. Т.е. из 376244 байт получить 367 KB, из 3194880 получить 3.04 MB, из 4704649216 байт получить 4.38 GB, etc. Суть алгоритма заключается в следующем. Если количество байт меньше 1024, то возвращаем его в заданном виде. Иначе заданную величину делим на 1024 (без остатка) до тех пор, пока она больше 1024000 - 1 (на байт меньше «среднего» мегабайта). При этом необходимо запомнинать количество итераций, которые означают порядок заданной величины (0 итераций соответствует килобайту, 1 - мегабайту, etc). Целой частью будет полученная величина, деленная еще на 1024, запоминаем ее. Далее, если целая часть из 3-х знаков, то дробной части к ней не прибавляем, если 2 знака, то дробная часть должна состоять из 1-го знака и из 2-х знаков, если целая часть из 1-го. Т.о., как нетрудно видеть, общее количество знаков должно быть равно трем. Дробная часть вычисляется по формуле (a - b * 1024) * 1000 / 1024 (которая еще делится на 10 и 100 при однозначной и двузначной целой частью соответсвенно), где a - заданная величина после всех преобразований, b - целая часть. Из полученных значений формируем ответ (при этом не следует забыть случай, когда дробная часть должна быть с лидирующим нулем). Ниже приведены реализации алгоритма на C++ и C#.

C++

#include
#include
#include
using namespace std;

#ifdef __GNUC__
typedef unsigned long long UInt64;
#else
typedef unsigned __int64 UInt64;
#endif

string ShortSize(UInt64 qw) {
     stringstream ret, ss;
     if(qw < 1024) { ret << qw; return ret.str() + " bytes"; }
     UInt64 c = 0, t = 1024 * 1000 - 1;
     while(qw > t) { qw /= 1024; c++; }
     UInt64 dw = qw / 1024;
     ret << dw;
     if(ret.str().length() < 3) {
          UInt64 uDec = (qw - dw * 1024) * 1000 / 1024;
          uDec /= 10;
          ret << ".";
          if(ret.str().length() == 3) uDec /= 10;
          ss << uDec;
          ret << string(4 - ret.str().length() - ss.str().length(), '0');
          ret << uDec;
     }
     string use[] = { "KB", "MB", "GB", "TB" };
     return ret.str() + " " + use[c];
}
C#

String ShortSize(UInt64 qw)
{
     if (qw < 1024) return qw.ToString() + " bytes";
     UInt64 c = 0, t = 1024 * 1000 - 1;
     while (qw > t) { qw /= 1024; c++; }
     UInt64 dw = qw / 1024;
     StringBuilder ret = new StringBuilder(dw.ToString());
     if (ret.Length < 3)
     {
          UInt64 uDec = (qw - dw * 1024) * 1000 / 1024;
          uDec /= 10;
          ret.Append(".");
          if (ret.Length == 3) uDec /= 10;
          ret.Append('0', 4 - ret.Length - uDec.ToString().Length);
          ret.Append(uDec.ToString());
     }
     String[] use = { "KB", "MB", "GB", "TB" };
     return ret + " " + use[c];
}

Previous post Next post
Up