Саша Ситников (shuffle_c) wrote,
Саша Ситников
shuffle_c

Categories:
  • Music:

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

Многие наверно знакомы с курьезом, связанным с трактованием широкораспространенных приставок системы СИ, примененных к единицам информации. Сколько байт в мегабайте? А сколько килобайт? Не смотря на несоответствие десятичных и двоичных величин (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 <string>
#include <sstream>
#include <iostream>
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];
}

Subscribe

  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments