0

I parsed a GET param named cb,66.45, and I converted it into float,got 66.45.

cb = request.GET.get("cb", '')
if re.match('^\d+(\.\d+)?$', cb):
    cb=float(cb)
    params['cb'] = cb

And then I used it to query db data, got empty.

products = Product.objects.filter(**params)

In fact ,I found when debugging, the query sql used 66.4500000000000028421709430404007434844970703125 instead of 66.45, and that caused my empty query result.

The cb is defined in Product model as below:

cb = models.DecimalField(max_digits=6, decimal_places=2, default=0)

Is there anything wrong? I am confused.

Uphie
  • 63
  • 1
  • 11
  • Float is not a precise type. So you should trim cb to 66.45 before execute the query. – Xiao Mar 17 '17 at 08:04
  • Have you tried using `cb` without typecasting to float, i.e use it as a string? – nik_m Mar 17 '17 at 08:20
  • It works when cb is used as a string, because mysql supports that. I tried to cast cb into float in python interpretor and got the same 66.45. Why does it becomes not precise when used in django query? And is it so dangerous to cast digits? – Uphie Mar 17 '17 at 09:22
  • May you can use `Decimal` type instead of float. `from decimal import Decimal` `cb=Decimal(cb)` – Renyuan wang Mar 17 '17 at 09:26
  • @Renyuanwang Yes,it works, thanks. Is it really caused by float casting ?But why I got the same 66.45 after float casting? In what conditons would float casting cause a precise result ? – Uphie Mar 17 '17 at 09:40
  • @Uphie PLS refer to this link http://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate. Actually, in system which need to precise calculation, you should use Integer/Long/Double instead of float. – Renyuan wang Mar 17 '17 at 10:00

1 Answers1

0

Thanks for @nik_m and @Renyuan wang. It works when cb is used as a string or cb=Decimal(cb).

I'm still confused.

enter image description here

I think django probably causes this problem, but I'm not sure.

Uphie
  • 63
  • 1
  • 11
  • You should not believe `print`. I guess there is a default format for `print` with float. Try `print ('%3.15f' % cb )` and you will get 66.450000000000003 – Renyuan wang Mar 17 '17 at 10:06
  • Yes, you're right. Django uses the most precise value of cb. Casting 66 ,got 66.000...000, and 66.4 got 66.400...40625. Sometimes casting won't make expected precise value, such as 66.4 and 45.43 ,and sometimes make expected precise values ,such as 66 and 45.5. It is required to use float casting carefully. – Uphie Mar 17 '17 at 10:56