По сути, попытка сохранить 64-битное значение в 32-битном значении приведет к потере точности, и компилятор правильно предупредит вас о проблеме. Вы действительно должны спросить: «Мне действительно нужна вся эта точность?»
Если вам не нужна точность, то "float output = Convert.ToSingle (inputAsDouble);" сделает свое дело - он просто округлит до ближайшего представимого значения одинарной точности.
Если вам нужна точность, но все же нужно, чтобы значение соответствовало 32-битным значениям, тогда вам нужно как-то ограничить диапазон. Например, если вы знаете, что ваше значение всегда будет в диапазоне от -1e-319 до 1e-319, то вы можете использовать математику с фиксированной запятой для преобразования между сохраненным 32-разрядным значением и двойным значением, которое необходимо использовать для расчеты. Возвращаемое таким образом двойное значение не сможет представлять все возможные числовые значения в вашем диапазоне, но вы будете иметь 32-разрядную гранулярность в этом ограниченном диапазоне, что на самом деле вполне приличная точность.
Например, вы можете создать вспомогательный класс, например:
struct FixedDouble
{
int storage;
public FixedDouble(double input)
{
storage = DoubleToStorage(input);
}
public double AsDouble
{
get
{
return StorageToDouble(storage);
}
}
const double RANGE = 1e-319;
public static int DoubleToStorage(double input)
{
Debug.Assert(input <= RANGE);
Debug.Assert(input >= -RANGE);
double rescaledValue = (input / RANGE) * int.MaxValue;
return (int)rescaledValue;
}
public static double StorageToDouble(int input)
{
double rescaledValue = ((double)input / (double)int.MaxValue) * RANGE;
return rescaledValue;
}
}
Этот код, вероятно, не будет работать как есть, потому что я только что быстро его выбил, но идея есть: в основном вы жертвуете полным диапазоном, который предлагает вам double, и вместо этого выбираете фиксированную гранулярность между двумя числами а 32-разрядное значение позволяет вам определить точку на числовой линии между этими двумя числами.