Some problems about float types


(Justin Rong) #1

mutate:

{
  set{
    _:42608 <test> "37.79697544"^^<xs:float>   .   #
  }
}

query:

{
  
  query(func: has(test))@filter(eq(test,37.79697544)){
    test
  }
}

respones:

  "data": {
    "query": [
      {
        "test": 37.796975
      }
    ]
  },

37.796975 != 37.79697544

if you use 37.796975 to query,

{
  
  query(func: has(test))@filter(eq(test,37.796975)){
    test
  }
}

it returns Your query did not return any results


(Paul Korzhyk) #2

I think if we remove rounding in the JSON serialization the rest will work as expected.

Equality tests with float numbers are broken “by design”.

We probably should file a bug about this. What do you think @MichelDiz?


(Michel Conrado (Support Engineer)) #3

Not sure.

He is using “eq”, equal to. By design seems logic to not return anything. For the query is not exactly the same as the one recorded. I would recommend using inequality combined with less than and greater than or equal.

{
  query(func: has(test))@filter(ge(test,37.796975) OR le(test,37.79697544)){
    test
  }
}

As it comes to float I do not know what the implication would be. Your call @paulftw . Let’s take the fractions of Bitcoin for example.

37.79697544 BTC = 242,165.22 USD
37.796975 BTC = 242,165,36 USD

0.14 cents difference. So every fraction of the float matters. In the sense that, they are not equal.

https://docs.dgraph.io/query-language#inequality

https://docs.dgraph.io/query-language#less-than-less-than-or-equal-to-greater-than-and-greater-than-or-equal-to

Cheers.


(Michel Conrado (Support Engineer)) #4

PS. Yeah, @paulftw I noticed right now that the correct thing was to return the recorded number completely. And that does not happen. It’s a bug or okay? (*) limitation?.

*I do not think it’s ok, it can be problematic for developers working with fractions.

{
  query(func: has(test))@filter(ge(test,37.796975) OR le(test,37.796975)){
    test
  }
{
  
  query2(func: has(test))@filter(eq(test,37.796975)){
    test
  }
}
    {
  
  query3(func: has(test))@filter(eq(test,37.79697544)){
    test
  }
}
}
{
  "data": {
    "query": [
      {
        "test": 37.796975 #should return the whole number 37.79697544
      }
    ],
    "query2": [],
    "query3": [
      {
        "test": 37.796975 #should return the whole number mainly here.
      }
    ]
  }

(Michel Conrado (Support Engineer)) #5

Adding one more references:

Dgraph records this like this

<_:uid2711> <test> "3.779697544E+01"^^<xs:float> .

Also supporting BigDecimal types could be related to this.

Also can be related https://github.com/dgraph-io/dgraph/issues/2377


(Paul Korzhyk) #6

One invariant I think everyone expects is:

when one query returns { “foo”: } then a query with eq(foo, ) must alway pick the original node.

No mater if is a string, integer, or float. As long as it is JSON serializable to the same string.

BigDecimal and RDF are probably unrelated although important issues.