2012-03-02 1 views
3

У меня есть сценарий, в котором у меня есть стандартный ящик, содержащий 3 банки. Для отображения и запросов я должен сообщать о десятичной сумме стандартной конфигурации. Это невозможно сказать, 1 коробок 3 банок, 1 коробок 2 банок ... и т.д.
Десятичная точность потери при попытке вычисления долей поля

Например, сначала у меня будет 1 коробка 3 банок
Я тогда удалить 1 может в результате в 0,66 повторяющейся коробки 3 банок
я затем удалить 1 больше, в результате чего может 0.33 повторяющейся коробка 3 банок
потом удалить окончательную банку в результате 0,0000000000000000000000000001 коробки из 3 банок

Когда я удаляю окончательный вариант, я хотел бы, чтобы значение было 0 ящиков из 3 банок, поскольку каждый из них теперь удален из оригинальной коробки. Я ценю, что есть потеря точности из-за того, что невозможно представить 0.33, повторяющийся, когда вы имеете дело с конечным числом бит.

Вопрос: Для людей, которые имеют больше опыта в системах, которые должны использовать округление (возможно, финансовые), каковы мои варианты решения этой проблемы? Как вы могли бы сделать удаление последнего, может означать, что ящик больше не существует?

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

Вот код, который я надеюсь, поможет с изложением проблемы еще немного: -

 static void Main(string[] args) 
    { 
     var box = new StandardBox(3); 
     var boxDetail = new BoxDetail(1.0m, box); 

     var allBoxes = new AllBoxes(); 
     allBoxes.AddBox(boxDetail); 
     allBoxes.RemoveItemFromBox(boxDetail, 1.0m); 
     Console.WriteLine(allBoxes); 
     allBoxes.RemoveItemFromBox(boxDetail, 1.0m); 
     Console.WriteLine(allBoxes); 
     allBoxes.RemoveItemFromBox(boxDetail, 1.0m); 
     Console.WriteLine(allBoxes); 
     Console.ReadLine(); 
    } 
} 

public class StandardBox 
{ 
    private decimal _quantity; 
    public StandardBox(decimal quantity){_quantity = quantity;} 
    public decimal Quantity {get { return _quantity; }} 
} 

public class BoxDetail 
{ 
    private decimal _quantity; 
    private StandardBox _box; 

    public BoxDetail(decimal quantity, StandardBox box) 
    { 
     _quantity = quantity; 
     _box = box; 
    } 

    public void RemoveItem(decimal quantity) 
    { 
     var newQuantity = quantity/_box.Quantity; 
     _quantity = _quantity - newQuantity; 
    } 

    public override string ToString() 
    { 
     return _quantity.ToString() + " of " + _box.Quantity.ToString(); 
    } 
} 

public class AllBoxes 
{ 
    private List<BoxDetail> allBoxes = new List<BoxDetail>(); 

    public AllBoxes(){} 

    public void AddBox(BoxDetail box){allBoxes.Add(box);} 

    public void RemoveItemFromBox(BoxDetail box, decimal quantity) 
    { 
     var boxDetailLineToModify = allBoxes.Find(b => b.Equals(box)); 
     boxDetailLineToModify.RemoveItem(quantity); 
    } 

    public override string ToString() 
    { 
     var results = string.Empty; 
     foreach (var box in allBoxes) 
     { 
      results += box.ToString() + "\n"; 
     } 
     return results; 
    } 
} 
+0

Вы можете использовать арифметическую библиотеку с бесконечной точностью. – SLaks

+0

Используйте double вместо десятичного. – jacknad

+0

Сначала я попытался удвоить, и результат удаления 3-го банка - это 1.11022302462516E-16 из 3 – lostinwpf

ответ

7

Мой подход к таким проблемам, это не делают это.

Это особенно верно, когда это финансовый материал.

Финансовый материал, как правило, довольно легко справляется - делайте всю свою работу в гроши, а не в долларах.

Моя первая реакция на вашу проблему состояла в том, чтобы хранить банки, а не коробки с банками.

+0

Я должен удовлетворять тот факт, что в определенных обстоятельствах количество банок в коробке может варьироваться. Я не уверен, справится ли с этим количество консервных банок - хотя я начинаю думать, что в конечном итоге лучше сохранить банки. – lostinwpf

1

Если вы просто хотите дисплей 0, а затем установить точность, когда вы показываете что-то разумное, скажем, 2 знака после запятой:

public override string ToString() 
{ 
    return _quantity.ToString("D2") + " of " + _box.Quantity.ToString(); 
} 

Если вы хотите сравнить значение на 0 (или любое другое значение), сравните разницу в отношении некоторого малого значения:

public bool AreEqual(double value1, double value2) 
{ 
    double EPSILON = 0.000001; 
    return Math.Abs(value1 - value2) < EPSILON; 
} 

bool IsZero = AreEqual(_quantity,0); 
2

Почему бы не использовать int для ваших количеств? Не похоже, что вы хотите разрешить удаление 1.078261563 (например) cans в любом случае - не так ли?

После прочтения немного больше, я думаю, что вижу здесь дилемму. Кажется, что вы комбинируете размер (максимальная емкость коробки), количество (то, что в настоящее время содержится в коробке), в просто процентное число (отношение количества к размеру). Если вы редизайн немного, отслеживая размер и количество и вычисления Процент полной, я думаю, что это будет убрать вещи:

class Box { 
    public decimal Size { get; private set; } 
    public decimal Quantity { get; private set; } 
    public decimal PercentFull { get { return this.Quantity/this.Size; } } 
    public Box(decimal size) { 
     this.Size = size; 
    } 
    public void Remove(decimal quantity) 
    { 
     this.Quantity -= quantity; 
    } 
    public void Add(decimal quantity) 
    { 
     this.Quantity += quantity; 
    } 
    public override string ToString() { 
     return this.PercentFull.ToString() + "% of " + this.Size.ToString(); 
      // Or, to be exact 
      // return this.Quantity.ToString() + " of " + this.Size.ToString(); 
    } 
} 

Он по-прежнему кажется, на основе вашей (возможно, облагороженная), например, что Size и Quantity бы лучше подходит для int - но математика работает одинаково в любом случае.

+0

Я просто выбрал банки как простой пример. Просто замените банки для литров и BOX для TUB, и я бы хотел взять 0.75 литров из TUB, и в этом случае десятичный смысл имеет больше смысла для меня. – lostinwpf

Смежные вопросы