github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/json/ryu/floatconv.gno (about)

     1  // Copyright 2018 Ulf Adams
     2  // Modifications copyright 2019 Caleb Spare
     3  //
     4  // The contents of this file may be used under the terms of the Apache License,
     5  // Version 2.0.
     6  //
     7  //    (See accompanying file LICENSE or copy at
     8  //     http://www.apache.org/licenses/LICENSE-2.0)
     9  //
    10  // Unless required by applicable law or agreed to in writing, this software
    11  // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    12  // KIND, either express or implied.
    13  //
    14  // The code in this file is part of a Go translation of the C code originally written by
    15  // Ulf Adams, which can be found at https://github.com/ulfjack/ryu. The original source
    16  // code is licensed under the Apache License 2.0. This code is a derivative work thereof,
    17  // adapted and modified to meet the specifications of the Gno language project.
    18  //
    19  // original Go implementation can be found at https://github.com/cespare/ryu.
    20  //
    21  // Please note that the modifications are also under the Apache License 2.0 unless
    22  // otherwise specified.
    23  
    24  // Package ryu implements the Ryu algorithm for quickly converting floating
    25  // point numbers into strings.
    26  package ryu
    27  
    28  import (
    29  	"math"
    30  )
    31  
    32  const (
    33  	mantBits32 = 23
    34  	expBits32  = 8
    35  	bias32     = 127
    36  
    37  	mantBits64 = 52
    38  	expBits64  = 11
    39  	bias64     = 1023
    40  )
    41  
    42  // FormatFloat64 converts a 64-bit floating point number f to a string.
    43  // It behaves like strconv.FormatFloat(f, 'e', -1, 64).
    44  func FormatFloat64(f float64) string {
    45  	b := make([]byte, 0, 24)
    46  	b = AppendFloat64(b, f)
    47  	return string(b)
    48  }
    49  
    50  // AppendFloat64 appends the string form of the 64-bit floating point number f,
    51  // as generated by FormatFloat64, to b and returns the extended buffer.
    52  func AppendFloat64(b []byte, f float64) []byte {
    53  	// Step 1: Decode the floating-point number.
    54  	// Unify normalized and subnormal cases.
    55  	u := math.Float64bits(f)
    56  	neg := u>>(mantBits64+expBits64) != 0
    57  	mant := u & (uint64(1)<<mantBits64 - 1)
    58  	exp := (u >> mantBits64) & (uint64(1)<<expBits64 - 1)
    59  
    60  	// Exit early for easy cases.
    61  	if exp == uint64(1)<<expBits64-1 || (exp == 0 && mant == 0) {
    62  		return appendSpecial(b, neg, exp == 0, mant == 0)
    63  	}
    64  
    65  	d, ok := float64ToDecimalExactInt(mant, exp)
    66  	if !ok {
    67  		d = float64ToDecimal(mant, exp)
    68  	}
    69  	return d.append(b, neg)
    70  }
    71  
    72  func appendSpecial(b []byte, neg, expZero, mantZero bool) []byte {
    73  	if !mantZero {
    74  		return append(b, "NaN"...)
    75  	}
    76  	if !expZero {
    77  		if neg {
    78  			return append(b, "-Inf"...)
    79  		}
    80  
    81  		return append(b, "+Inf"...)
    82  	}
    83  
    84  	if neg {
    85  		b = append(b, '-')
    86  	}
    87  	return append(b, "0e+00"...)
    88  }
    89  
    90  func boolToInt(b bool) int {
    91  	if b {
    92  		return 1
    93  	}
    94  	return 0
    95  }
    96  
    97  func boolToUint32(b bool) uint32 {
    98  	if b {
    99  		return 1
   100  	}
   101  	return 0
   102  }
   103  
   104  func boolToUint64(b bool) uint64 {
   105  	if b {
   106  		return 1
   107  	}
   108  	return 0
   109  }
   110  
   111  func assert(t bool, msg string) {
   112  	if !t {
   113  		panic(msg)
   114  	}
   115  }
   116  
   117  // log10Pow2 returns floor(log_10(2^e)).
   118  func log10Pow2(e int32) uint32 {
   119  	// The first value this approximation fails for is 2^1651
   120  	// which is just greater than 10^297.
   121  	assert(e >= 0, "e >= 0")
   122  	assert(e <= 1650, "e <= 1650")
   123  	return (uint32(e) * 78913) >> 18
   124  }
   125  
   126  // log10Pow5 returns floor(log_10(5^e)).
   127  func log10Pow5(e int32) uint32 {
   128  	// The first value this approximation fails for is 5^2621
   129  	// which is just greater than 10^1832.
   130  	assert(e >= 0, "e >= 0")
   131  	assert(e <= 2620, "e <= 2620")
   132  	return (uint32(e) * 732923) >> 20
   133  }
   134  
   135  // pow5Bits returns ceil(log_2(5^e)), or else 1 if e==0.
   136  func pow5Bits(e int32) int32 {
   137  	// This approximation works up to the point that the multiplication
   138  	// overflows at e = 3529. If the multiplication were done in 64 bits,
   139  	// it would fail at 5^4004 which is just greater than 2^9297.
   140  	assert(e >= 0, "e >= 0")
   141  	assert(e <= 3528, "e <= 3528")
   142  	return int32((uint32(e)*1217359)>>19 + 1)
   143  }