The Crystal Programming Language Forum

Print Float64 without fractional digit when the fractional digit is absent

Hello,

I have a variable of type Float64 that can have fractional digits or not. For example, it could be
4, 4.5, 4.75 etc.

I need to return its value as a string. So I do:

myvar = 4.f_64
myvar_str = "#{myvar}"

puts myvar_str ## this prints 4.0. Can I have it print as 4 (without the 0)?

I looked at decimal_places option. But it appears that would not work since I want 4.3 to be printed as 4.3. I want 4.0 to be printed as 4. How can I do that?

Thank you for your help.

How do you want 0.3+0.6+0.1 to be printed, btw?

As it does, 0.999999999. The main thing I want is that if there is just a zero then it should ignore it.

I can do:

myvar = somefloat
myvar_int = somefloat.to_i
if myval_int == myvar
     return myvar_int.to_s
else 
     return myvar.to_s
end

Wondering if there is a built in option for this. This is how Javascript does it (of course, not a language to be emulated :))

maybe convert myval_int back to float and subtract from myval and check if it is 0.0

Given the requirement is you only want this to happen for integer like values, i.e. that are even, you could do like:

def print(value : Number)
  puts value.format decimal_places: value.remainder(2).zero? ? 0 : 1
end
 
print 4_f64 # => 4
print 4.20  # => 4.2
print 3.14  # => 3.1
print 4.7   # => 4.7

However this raises the question of, should https://crystal-lang.org/api/Number.html#format(separator=’.’,delimiter=’,’,decimal_places:Int?=nil,*,group:Int=3,only_significant:Bool=false):String-instance-method

actually print the .0 if you have only_significant: true?

Trailing zeros are omitted if only_significant is true.

4 == 4.0 is technically the .0 isn’t significant, and by the description of that arg, I would have thought it wouldn’t be printed.

Thank you @Blacksmoke16. I have not looked at the source code, so this is not about implementation of only_significant. But, mathematically speaking, the notion of significance is very confusing. I don’t understand it. According to https://www.purplemath.com/modules/rounding2.htm the zero in 4.0 is significant. But the zeroes in 1000 are not significant. Weird!

If possible, I don’t want to round the numbers when there are decimal places, like this one does. Are there some circumstances in which my solution will not work?

This might be good because then I am comparing a float with a float; unless Crystal automatically convert an Int32 to a Float64 when comparing them?

Can just omit the decimal_places argument in that case.

“%.16g” % myvar

might do what you want.

I needed the same feature, here is my implementation:

struct Float
 def trim_zero
   self == self.to_i ? self.to_i : self
 end  
end

x = 4.0
y = 5.2

puts "x = #{x.trim_zero}" # => "x = 4"
puts "y = #{y.trim_zero}" # => "y = 5.2"

@mselig This is cool. Where can I read about that formatting (the g option). I did not know about that one.

Thank you.

Have a look at the documentation for Kernel::sprintf first. You should also know that the format string is based on printf(3), from the C language and has been around for decades. You can also look at Wikipedia though it is actually about C, not Crystal, and also includes lots of extensions which do not apply to Crystal. It does say about “g”:

This type differs slightly from fixed-point notation in that insignificant zeroes to the right of the decimal point are not included. Also, the decimal point is not included on whole numbers.

which is a better description than Crystal (or Ruby’s) documentation.

This is very helpful. Thank you.