Uploaded image for project: 'Go Driver'
  1. Go Driver
  2. GODRIVER-2046

Return clearer error when truncating a float64 to float32 without the truncate tag

    • Type: Icon: Improvement Improvement
    • Resolution: Done
    • Priority: Icon: Minor - P4 Minor - P4
    • None
    • Affects Version/s: 1.4.7, 1.5.1, 1.5.2, 1.5.3
    • Component/s: BSON
    • Labels:
      None
    • Environment:
      Windows
      Alpine Linux/Docker Containers
      Go 1.16.5
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?

      Motivation

      If attempting to unmarshal a float64 into a float32 results in truncation, and the destination does not have the truncate tag, the error errCannotTruncate is returned. This error consists of the message "float64 can only be truncated to an integer type when truncation is enabled". The error message is misleading. A float64 can be unmarshaled into a float32 if the truncate tag is present.

      Scope
      Update the error message to apply to this case. Consider changing to the following: "float64 can only be truncated when the truncate tag is present"

      Original ticket description

      We've run across an issue where the truncation logic in the BSON lib is causing an issue due to a floating point rounding error when trying to validate a float32 value when comparing float64(float32(f)) to the mongo returned float64(f).

      Here's the minimum reproducible showcasing that 0.1 returns incorrectly: https://play.golang.org/p/eYANaXFKVk9

      package main
      
      import (
      	"fmt"
      )
      
      func main() {
      	a := float64(0.1) // What type is coming back from mongo
      	b := float32(a) // What type is being conformed based on specified type in struct
      	c := float64(b) // The conversion back, which causes the rounding point error going from f32 -> f64
      	
      	fmt.Printf("%#+v | %#+v | %#+v\n", a, b, c)
      	fmt.Printf("not equal? %t\n", float64(float32(a)) != a)
      }
      

      Returns:
      0.1 | 0.1 | 0.10000000149011612
      not equal? true

      This is occurring here: https://github.com/mongodb/mongo-go-driver/blob/49af6e279ffe534210dca95e375d372517145e44/bson/bsoncodec/default_value_decoders.go#L480

            Assignee:
            Unassigned Unassigned
            Reporter:
            matt@linc-ed.com Matt Hartstonge
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: