Skip to content

Conversation

@babyTsakhes
Copy link
Collaborator

msgpack_ext: add string() for decimal

Added a decimal type conversion function to a string, added tests for this function. Fixed name of function. Add test for decimal convertion. I tried to write an optimized version, but there is a problem with values when working with BCD, insignificant zeros after the decimal point are lost.

Added #322

Added a decimal type conversion function to a string, added tests for this function.

Added #322
Added a decimal type conversion function to a string, added tests for this function. Fixed buffer for int64.

Added #322
Added a decimal type conversion function to a string, added tests for this function. Fixed name of function.

Added #322
Added a decimal type conversion function to a string, added tests for this function. Fixed name of function. Add test for decimal convertion.

Added #322
@babyTsakhes
Copy link
Collaborator Author

TestTarantoolBCDCompatibility is FAIL.

@babyTsakhes
Copy link
Collaborator Author

return d.Decimal.String() - this method true, but slowly. I will correct the code and comments, at the moment I am looking for a solution to the problem.

Added a datetime type conversion function to a string, added tests for this function.

Added #322
Copy link
Collaborator

@oleg-jukovec oleg-jukovec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, squash commits into a single relevant-one.

return ptr.UnmarshalMsgpack(b)
}

// This method converts Datetime to String - formats to ISO8601.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The go-idiomatic way to comment a method.

Suggested change
// This method converts Datetime to String - formats to ISO8601.
// String converts Datetime to String - formats to ISO8601.

}

func TestDatetimeString(t *testing.T) {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Comment on lines 161 to 307
exponent := d.Decimal.Exponent()

// If exponent is positive, then we use the standard method.
if exponent > 0 {
return d.Decimal.String()
}

scale := -exponent

if !coefficient.IsInt64() {
return d.Decimal.String()
}

int64Value := coefficient.Int64()

return d.stringFromInt64(int64Value, int(scale))
}

// StringFromInt64 is an internal method for converting int64
// and scale to a string (for numbers up to 19 digits)
func (d Decimal) stringFromInt64(value int64, scale int) string {

var buf [48]byte
pos := 0

negative := value < 0
if negative {
if value == math.MinInt64 {
return d.handleMinInt64(scale)
}
buf[pos] = '-'
pos++
value = -value
}

str := strconv.FormatInt(value, 10)
length := len(str)

if scale == 0 {
if pos+length > len(buf) {
return d.Decimal.String()
}
copy(buf[pos:], str)
pos += length
return string(buf[:pos])
}

if scale >= length {

required := 2 + (scale - length) + length
if pos+required > len(buf) {
return d.Decimal.String()
}

buf[pos] = '0'
buf[pos+1] = '.'
pos += 2

zeros := scale - length
for i := 0; i < zeros; i++ {
buf[pos] = '0'
pos++
}

copy(buf[pos:], str)
pos += length
} else {

integerLen := length - scale

required := integerLen + 1 + scale
if pos+required > len(buf) {
return d.Decimal.String()
}

copy(buf[pos:], str[:integerLen])
pos += integerLen

buf[pos] = '.'
pos++

copy(buf[pos:], str[integerLen:])
pos += scale
}

return string(buf[:pos])
}
func (d Decimal) handleMinInt64(scale int) string {
const minInt64Str = "9223372036854775808"

var buf [48]byte
pos := 0

buf[pos] = '-'
pos++

length := len(minInt64Str)

if scale == 0 {
if pos+length > len(buf) {
return "-" + minInt64Str // Fallback.
}
copy(buf[pos:], minInt64Str)
pos += length
return string(buf[:pos])
}

if scale >= length {
required := 2 + (scale - length) + length
if pos+required > len(buf) {
// Fallback.
result := "0." + strings.Repeat("0", scale-length) + minInt64Str
return "-" + result
}

buf[pos] = '0'
buf[pos+1] = '.'
pos += 2

zeros := scale - length
for i := 0; i < zeros; i++ {
buf[pos] = '0'
pos++
}

copy(buf[pos:], minInt64Str)
pos += length
} else {
integerLen := length - scale
required := integerLen + 1 + scale
if pos+required > len(buf) {
return d.Decimal.String() // Fallback
}

copy(buf[pos:], minInt64Str[:integerLen])
pos += integerLen

buf[pos] = '.'
pos++

copy(buf[pos:], minInt64Str[integerLen:])
pos += scale
}

return string(buf[:pos])
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code works faster than if you call the method d.Decimal.String() . Is it okay to leave it?

Copy link
Collaborator

@oleg-jukovec oleg-jukovec Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, rename it to String and add benchmarks to compare with shopspring.Decimal if so.

Added a datetime Interval type conversion function to a string, added tests for this function.

Added #322
Added a benchmark, which shows that the code is optimized two or more times for string conversion than the code from the library.

Added #322
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants