2

I have a big.float which I'm encoding into JSON . However the JSON always end up showing the float in scientific notation rater than decimal notation. I can fix this by changing the JSON to be a string rather than a number and using float.Text('f'), however I would really prefer to keep the type as a number.

I was a taking a look at float.Format but I don't believe this is suitable.

A really condensed gist of what I'm doing is below. I do a lot more modification of the value of supply before encoding it to json.

type TokenSupply struct {
   TotalSupply  *big.Float  `json:"totalSupply, omitempty"`
}
supply := Float.NewFloat(1000000)
json.NewEncoder(w).Encode(TokenSupply{supply})

This returns:

{"totalSupply":"1e+06"}
7
  • Show the exact generated JSON. Commented Nov 17, 2017 at 1:29
  • {"totalSupply":"1e+06"} I'd like for this to be printed as 1000000 Note that in this case the number is an integer but it could be a float with a large number of decimals. Commented Nov 17, 2017 at 1:34
  • 1
    So it's a string not a number :-S Commented Nov 17, 2017 at 1:40
  • I've updated the original post to show what I'm doing. The type of value should be a float yet gets printed as a string in scientification notation through Encode. If I change the value in the struct to be a string, and then write the value using json.NewEncoder(w).Encode(TokenSupply{supply.Text('f', 0)}) it gives me the number in decimal form but alas still a string =/ Commented Nov 17, 2017 at 1:46
  • Do you really need a big.Float instead of a float64? What kind of numbers are you working with here? Commented Nov 17, 2017 at 1:49

2 Answers 2

2

big.Float is marshaled to string when converted to a JSON type

https://golang.org/pkg/encoding/json/#Marshal

Marshal traverses the value v recursively. If an encountered value implements the Marshaler interface and is not a nil pointer, Marshal calls its MarshalJSON method to produce JSON. If no MarshalJSON method is present but the value implements encoding.TextMarshaler instead, Marshal calls its MarshalText method and encodes the result as a JSON string. The nil pointer exception is not strictly necessary but mimics a similar, necessary exception in the behavior of UnmarshalJSON.

https://golang.org/pkg/math/big/#Float.MarshalText

func (x *Float) MarshalText() (text []byte, err error)

What can you do about it?

since your float may be more than 64 bits it won't play well with other languages that have to read the JSON value as a number. I'd suggest you keep the number as a string.

Sign up to request clarification or add additional context in comments.

Comments

0

Caveats about encoding numbers that don't fit into 64 bits aside, here is how you could marshal a big.Float as a JSON number by wrapping it in a custom type that implements json.Marshaler. The key is that you can implement theMarshalJSON method anyway you like, as long as it emits valid JSON:

package main

import (
  "encoding/json"
  "fmt"
  "math/big"
)

type BigFloatNumberJSON struct{ *big.Float }

func (bfn BigFloatNumberJSON) MarshalJSON() ([]byte, error) {
  // Use big.Float.String() or any other string converter
  // that emits a valid JSON number here...
  return []byte(bfn.String()), nil
}

func main() {
  totalSupply := new(big.Float).SetFloat64(1000000)
  obj := map[string]interface{}{
    "totalSupply": BigFloatNumberJSON{totalSupply},
  }
  bytes, err := json.Marshal(&obj)
  if err != nil {
    panic(err)
  }
  fmt.Println(string(bytes))
  // => {"totalSupply":1000000}
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.