"Как бы ты реализовывал тип данных, который даёт значение с точностью до 100 знаков после запятой?"
Это была очень крупная известная компания, которая работает со своим собственным движком.
Из структуры вопроса видно, что он подразумевает размышления.
Собеседующему интересно, какие варианты ты предложишь и как ты к ним придёшь. Даже если ты ошибёшься - это будет не так страшно, если ты действительно показываешь обоснованную цепочку выводов, к которым приходишь. Поэтому не бойтесь размышлять вслух.
Первое, что приходит мне в голову - это использование Nuget пакета для подобной ситуации.
Я знаю точно, что существует решение для случаев, когда тебе нужно очень большое целочисленное число. Пакет называется BigInteger. Я бы поискал нечто подобное в интернете.
Спойлер: решения реально существуют. Библиотеки Mpir.NET и Math.NET Numerics.
Второе, что приходит мне в голову - это ресёрч библиотеки Mathf, в поисках уже готового решения.
Спойлер: я не нашёл. Но вариант звучит вполне разумно для собеседующего.
Третье - попробовать реализовать решение самостоятельно. Как это сделать? Давайте посмотрим на саму реализацию.
using System;
using System.Text;
public static string DivideLong(long a, long b, int digits)
{
if (b == 0)
throw new DivideByZeroException();
// negative будет true, если знаки чисел a и b различаются (одно положительное, другое отрицательное)
// Знак ^ - это побитовая операция XOR (исключающее ИЛИ)
// После этого приводим их абсолютными значениями (убираем минус в начале)
bool negative = (a < 0) ^ (b < 0);
a = Math.Abs(a);
b = Math.Abs(b);
// Целая часть
long integerPart = a / b;
// Остаток
long remainder = a % b;
StringBuilder result = new();
// Добавляется знак минус, если результат отрицательный и при этом не является нулём (условие (integerPart != 0 || remainder != 0) гарантирует, что для -0 минус ставиться не будет
if (negative && (integerPart != 0 || remainder != 0))
result.Append('-');
result.Append(integerPart);
// Разберём детальнее ниже
if (digits > 0)
{
result.Append('.');
for (int i = 0; i < digits; i++)
{
remainder *= 10;
long digit = remainder / b;
result.Append(digit);
remainder %= b;
}
}
return result.ToString();
}
Для каждого требуемого знака после запятой выполняется:
- Остаток умножается на 10;
- Определяется текущая цифра как целая часть от деления полученного числа на делитель b;
- Цифра добавляется к строке;
- Остаток заменяется остатком от деления на b.
Этот цикл повторяется ровно digits раз, формируя последовательность десятичных знаков без округления.
У этого решения есть свои слабые места. Я вижу несколько редких ситуаций, которые могут сломать логику. Но это здесь не так важно.
Главное, что вы:
- Понимаете суть алгоритма и на чём он строится.
- Примерно понимаете как нужно отвечать на вопросы подобного рода.
🚀 Пост Guru Unity: @Minerope