Nano Hash - криптовалюты, майнинг, программирование

Исключение переполнения при делении двух десятичных знаков в .NET

У меня возникла проблема с попыткой разделить два десятичных знака, а затем отобразить результат. Досадно, что это происходит только на нашем сервере, и, кажется, он отлично работает, если я запускаю код локально. Это код, который я пытаюсь запустить


decimal dOne = -966.96M;
decimal dTwo = 2300M;

decimal dResult = Decimal.Round((dOne / dTwo), 28, 
                               MidpointRounding.AwayFromZero);

Результирующее число (сгенерированное из калькулятора Windows) равно

-0.43346086956521739130434782608696

Это всегда приводит к исключению переполнения:

System.OverflowException: Value was either too large or too small for a Decimal.
   at System.Decimal.FCallDivide(Decimal& result, Decimal d1, Decimal d2)
   at System.Decimal.op_Division(Decimal d1, Decimal d2)

Это имеет смысл, поскольку результирующее число имеет длину более 32 знаков после запятой, а десятичное число может содержать только до 28 знаков. введите в памяти, прежде чем округлить и сохранить. Я также пытался преобразовать его непосредственно в строку, а не хранить в десятичном виде, но у него та же проблема.

Любые идеи? Я сделал что-то явно глупое (скорее всего), и есть ли лучший способ выполнить этот расчет?

08.07.2010

  • может быть, у вас 32-битный сервер, а 64-битная рабочая станция? 08.07.2010
  • Если только, это 64-битный сервер на базе xeon с сервером 2003 x64 и .net 3.5 :( 08.07.2010
  • Наверняка для округления до 28 разрядов нужно смотреть на 29-ю цифру. Это все еще делает это, если вы попросите 27? 08.07.2010

Ответы:


1

Попробуйте преобразовать в double перед расчетом и обратно в decimal после, если вам нужно:

decimal dOne = -966.96M;
decimal dTwo = 2300M;

double one = (double)dOne;
double two = (double)dTwo;

double result = one / two;

decimal dResult = (decimal)result; // Additional rounding may be necessary
08.07.2010
  • Я отмечаю это как свой ответ, так как после разговора с моими коллегами это происходит только в этом конкретном случае, и мы можем справиться с потерей точности. Решил поставить try/catch для переполнения и преобразовать в двойное, если это произойдет на данный момент ... хотя, если есть лучший ответ, я бы предпочел добавить его в будущем :) 08.07.2010

  • 2

    Это должно работать нормально. Не гарантируется, что деление вернет точно точную версию — например, 1 / 3 м вполне подойдет.

    Результат явно не выходит за пределы диапазона decimal, поэтому мне кажется, что на вашем сервере происходит что-то странное.

    Нужно проверить одну вещь: это Decimal.Round выдает исключение или само подразделение? Поместите их в отдельные утверждения, чтобы узнать.

    08.07.2010
  • Спасибо за комментарий, Джон - изначально я имел их в отдельных строках и пробовал с Decimal.Round и без него, поэтому я почти уверен, что округление не проблема. Это определенно странно, поскольку один и тот же код работает в песочнице и на моем рабочем столе.. разочаровывающая проблема;) 08.07.2010

  • 3

    Если это происходит на вашем сервере (где вы не можете отлаживать). Вы действительно уверены, что проблема именно в этих строках?

    Может быть, вы можете поместить оператор try-catch только в один оператор Decimal.Round и вместо этого вернуть какое-то странное значение. Этот код вы можете запустить на своем сервере еще раз, чтобы увидеть, действительно ли вызывается этот оператор catch или исключение может произойти где-то еще.

    08.07.2010

    4

    Я посмотрел на Decimal.Round через Reflector и, насколько я вижу, он никогда не выдает OverflowException, поэтому я держу пари, что исключение исходит от подразделения. Можете ли вы отредактировать свой ответ, чтобы включить трассировку стека?

    Кроме того, вы абсолютно уверены, что числитель и знаменатель точно такие, как вы написали? Попробуйте отследить их на консоли или в файле журнала при возникновении исключения.

    Вы можете сделать что-то вроде этого:

    decimal dOne = -966.96M; 
    decimal dTwo = 2300M;  
    try
    {
      decimal dResult = Decimal.Round((dOne / dTwo), 28, MidpointRounding.AwayFromZero); 
    }
    catch (OverflowException)
    {
      Console.WriteLine(dOne);
      Console.WriteLine(dTwo);
    }
    

    Изменить: кажется, я нашел код FCallDivide в SSCLI. Однако, скорее всего, в релизной версии .NET Framework все будет по-другому, но из того, как это было сделано в SSCLI, я вижу, что исключение переполнения будет генерироваться множеством разных способов. Код довольно сложный. Если вы сможете составить короткую, но полную программу, демонстрирующую проблему, я отправлю ее как ошибку в Microsoft. Возможно, в этих входных данных есть определенный битовый шаблон, который сбивает с толку алгоритм.

    08.07.2010
  • Я добавил немного больше информации - после этого он возвращается к другому коду, который не имеет отношения. Я добавил журнал, чтобы вытащить числа перед делением, и это те, которые он использует. На данный момент я смотрю на решение двойного преобразования, опубликованное Томасом, так как мне действительно не нужно больше, чем около 10/12 DP в качестве точности, и похоже, что оно сработает ... но нужно больше его тестировать. 08.07.2010
  • Ладно, это явно происходит внутри подразделения. Это довольно странно. Какую версию фреймворка вы используете локально и на сервере? Я попытаюсь придумать другие способы устранения этой неполадки, но это будет сложно. Я посмотрю, не смогу ли я найти код для метода FCallDivide. 08.07.2010
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..