Как мне читать / записывать C # BigIntegers в / из файла? - PullRequest
4 голосов
/ 23 июля 2011

в одном из моих классов у меня есть подпрограмма, которая читает и записывает массив типа Decimal (используя методы BinaryReader / BinaryWriter * ReadDecimal() и Write(), например:

BinaryReader inputReader = new BinaryReader(File.OpenRead(BaseFilePath));
for (int x = 0; x < 6; x++) {
    for (int y = 0; y < m_Codes[x].GetLength(0); y++) {
        for (int z = 0; z < m_Codes[x].GetLength(1); z++) {
            m_Codes[x][y, z] = inputReader.ReadDecimal();
        }
    }
}

и

for (int x = 0; x < 6; x++) {
    for (int y = 0; y < m_Codes[x].GetLength(0); y++) {
        for (int z = 0; z < m_Codes[x].GetLength(1); z++) {
            outputWriter.Write(m_Codes[x][y, z]);
        }
    }
}

.. как вы можете видеть, во время разработки известно только первое измерение, остальные зависят от времени выполнения.

В идеальном мире я бы заменил ReadDecimal() на ReadBigInteger() и что-то подобное для методов записи, но это не поддерживается в классах Stream; Я предполагаю, что это потому, что BigInteger может быть любой длины.

Самое лучшее, что я могу придумать, - это «вручную написать» код BigInteger, преобразовав его в массив byte[], затем записав длину этого массива, затем записав каждый байт в сам массив (и выполнив обратный читать, чтобы прочитать в)

Два вопроса:

1) Это лучший способ?

2) Меня в первую очередь мотивирует желание повысить производительность; Бои BigInteger даже лучше, чем десятичные, если вообще?

Ответы [ 2 ]

4 голосов
/ 23 июля 2011

Существует один довольно простой подход: вызовите BigDecimal.ToByteArray для сериализации и конструктор BigDecimal(byte[]) при десериализации. По общему признанию это заканчивает тем, что копировало данные, но я все еще ожидал бы, что это будет достаточно быстро.

Что вас больше беспокоит: производительность сериализации или арифметическая производительность?

Что касается любых различий в скорости между BigInteger и decimal - вы должны проверить это для операций, которые вы действительно хотите выполнить, зная, что они будут вести себя по-разному (например, деление 3 на 2, очевидно, даст другой ответ для каждый тип).

2 голосов
/ 23 июля 2011

Вы можете преобразовать в строку (BigInteger.ToSting()), а затем записать эту строку (так как строки напрямую поддерживаются с BinaryReader и BinaryWriter это избавляет от необходимости выполнять какое-либо кодирование / декодирование самостоятельно).

Затем преобразовать его обратно с помощью BigInteger.Parse.

Что касается производительности: я думаю, вам нужно измерить для интересующих вас случаев.

При относительно небольших значениях (скажем, abs (значение) <2 <sup>128 ) я бы ожидал, что производительность BigInteger будет в пределах пары порядков long производительность (т.е. не более чем в ~ 500 раз медленнее). Но когда BigInteger экземпляры получат более крупные операции, они будут занимать больше времени (необходимо обрабатывать больше битов) С другой стороны, decimal должен иметь достаточно стабильную производительность во всех масштабах, но он может быть намного медленнее, чем long для чисел в пересечении их диапазонов (decimal - гораздо более сложное представление: коэффициенты масштабирования и сохранение фактические значимые цифры в расчетах, но нет понимания влияния этой сложности).

И помните: BigDecimal точно - оно никогда не округляется; decimal является приблизительным - данные могут падать с конца и выбрасываться. Кажется маловероятным, что какая-либо одна бизнес-проблема поддержит либо.

...