Variable floating-point precision format string - go

I'm trying to print floating point numbers as percentages, and I'd like for the number of digits after the decimal place to vary as needed. Currently I have:
fmt.Printf("%.2f%%\n", 100*(value/total))
The problem is that if my percentage is, say, exactly 50, I will get the following output:
50.00%
While what I want is to get:
50%
Is there any way for the format string to indicate that a maximum of 2 digits of precision should be used, but only if needed?

There's no direct solution with the fmt package.
But you can remove the dot and zeros at end with a regular expression:
r, _ := regexp.Compile(`\.?0*$`)
fmt.Printf("%s%%\n", r.ReplaceAllString(fmt.Sprintf("%.2f", 100*(value/total)),""))
Bonus: the same regex works for any number of trailing zeros.
Side note: You'll display 50.0041 the same way than 50, which might be a little misleading.

There's no way to do that inside fmt with e.g. another flag or what have you. You'll have to write out the logic yourself. You could do something like:
var final string
doubledecimal := fmt.Sprintf("%.2f", 100*value/total)
if doubledecimal[len(doubledecimal)-2:] == "00" {
final = doubledecimal[:len(doubledecimal)-3]
} else {
final = doubledecimal
}
fmt.Printf("%s%%\n, final)
You could similarly use strings.Split to split on the decimal point and work from there.
You could even adjust this to turn 50.10% into 50.1%.
doubledecimal := fmt.Sprintf("%.2f", 100*value/total)
// Strip trailing zeroes
for doubledecimal[len(doubledecimal)-1] == 0 {
doubledecimal = doubledecimal[:len(doubledecimal)-1]
}
// Strip the decimal point if it's trailing.
if doubledecimal[len(doubledecimal)-1] == "." {
doubledecimal = doubledecimal[:len(doubledecimal)-1]
}
fmt.Printf("%s%%\n", doubledecimal)

One way could be to have an if statement controlling the print output, i.e. if the result is cleanly divisible by 1 (result%1 == 0) then print the result to no decimal places. Otherwise print to .2f as you've done above. Not sure if there is a shorter way of doing this, but I think this should work.

Related

How to verify that the last character in a string is a number

I need to check if the last character in a string is a digit, and if so, increment it.
I have a directory structure of /u01/app/oracle/... and that's where it goes off the rails. Sometimes it ends with the version number, sometimes it ends with dbhome_1 (or 2, or 3), and sometimes, I have to assume, it will take some other form. If it ends with dbhome_X, I need to parse that and bump that final digit, if it is a digit.
I use split to split the directory structure on '/', and use include? to check if the final element is something like "dbhome". As long as my directory structure ends with dbhome_X it seems to work. As I was testing, though, I tried a path that ended with dbhome, and found that my check for the last character being a digit didn't work.
db_home = '/u01/app/oracle/product/11.2.0/dbhome'
if db_home.split('/')[-1].include?('dbhome')
homedir=db_home.split('/')[-1]
if homedir[-1].to_i.is_a? Numeric
homedir=homedir[0...-1]+(homedir[-1].to_i+1).to_s
new_path="/"+db_home.split('/')[1...-1].join("/")+"/"+homedir.to_s
end
else
new_path=db_home+"/dbhome_1"
end
puts new_path
I did not expect the output to be /u01/app/oracle/11.2.0/product/dbhom1 - it seems to have fallen into the if block that added 1 to the final character.
If I set the initial path to /u01/app/.../dbhome_1, I get the expected /u01/app/.../dbhome_2 as the output.
You could use a regular expression to make matching a tad bit easier
if !!(db_home[/.*dbhome.*\z]) ..
You could use regex's
/[0-9]$/.match("How3").nil?
I need to check if the last character in a string is a digit, and if
so, increment it.
This is one option:
s = 'string9'
s[-1].then { |last| last.to_i.to_s == last ? [s[0..-2], last.to_i+1].join : s }
#=> "string10"
'/u01/app/11.2.0/dbhome'.sub(/\d\z/) { |s| s.succ }
#=> "/u01/app/11.2.0/dbhome"
'/u01/app/11.2.0/dbhome9'.sub(/\d\z/) { |s| s.succ }
#=> "/u01/app/11.2.0/dbhome10"
This is a starting point if you're running Ruby v2.6+:
fname = 'filename1'
fname[/\d+$/].then { |digits|
fname[/\d+$/] = digits.to_i.next.to_s if digits
}
fname # => "filename2"
And it's safe if the filename doesn't end with a digit:
fname = 'filename'
fname[/\d+$/].then { |digits|
fname[/\d+$/] = digits.to_i.next.to_s if digits
}
fname # => "filename"
I'm not sure if I like doing it that way better than the more traditional way which works with much older Rubies:
digits = fname[/\d+$/]
fname[/\d+$/] = digits.to_i.next.to_s if digits
except for the fact that digits gets stuck into the variable space after only being used once. There's probably worse things that happen in my code though.
This is taking advantage of String's [] and []= methods.

Automatically increment filename VideoWriter MATLAB

I have MATLAB set to record three webcams at the same time. I want to capture and save each feed to a file and automatically increment it the file name, it will be replaced by experiment_0001.avi, followed by experiment_0002.avi, etc.
My code looks like this at the moment
set(vid1,'LoggingMode','disk');
set(vid2,'LoggingMode','disk');
avi1 = VideoWriter('X:\ABC\Data Collection\Presentations\Correct\ExperimentA_002.AVI');
avi2 = VideoWriter('X:\ABC\Data Collection\Presentations\Correct\ExperimentB_002.AVI');
set(vid1,'DiskLogger',avi1);
set(vid2,'DiskLogger',avi2);
and I am incrementing the 002 each time.
Any thoughts on how to implement this efficiently?
Thanks.
dont forget matlab has some roots to C programming language. That means things like sprintf will work
so since you are printing out an integer value zero padded to 3 spaces you would need something like this sprintf('%03d',n) then % means there is a value to print that isn't text. 0 means zero pad on the left, 3 means pad to 3 digits, d means the number itself is an integer
just use sprintf in place of a string. the s means String print formatted. so it will output a string. here is an idea of what you might do
set(vid1,'LoggingMode','disk');
set(vid2,'LoggingMode','disk');
for (n=1:2:max_num_captures)
avi1 = VideoWriter(sprintf('X:\ABC\Data Collection\Presentations\Correct\ExperimentA_%03d.AVI',n));
avi2 = VideoWriter(sprintf('X:\ABC\Data Collection\Presentations\Correct\ExperimentB_002.AVI',n));
set(vid1,'DiskLogger',avi1);
set(vid2,'DiskLogger',avi2);
end

Ruby String pad zero OPE ID

I'm working with OPE IDs. One file has them with two trailing zeros, eg, [998700, 1001900]. The other file has them with one or two leading zeros for a total length of six, eg, [009987, 010019]. I want to convert every OPE ID (in both files) to an eight-digit string with exactly two leading zeros and however many zeros at the end to get it to be eight digits long.
Try this:
a = [ "00123123", "077934", "93422", "1231234", "12333" ]
a.map { |n| n.gsub(/^0*/, '00').ljust(8, '0') }
=> ["00123123", "00779340", "00934220", "001231234", "00123330"]
If you have your data parsed and stored as strings, it could be done like this, for example.
n = ["998700", "1001900", "009987", "0010019"]
puts n.map { |i|
i =~ /^0*([0-9]+?)0*$/
"00" + $1 + "0" * [0, 6 - $1.length].max
}
Output:
00998700
00100190
00998700
00100190
This example on codepad.
I'm note very sure though, that I got the description exactly right. Please check the comments and I correct in case it's not exactly what you were looking for.
With the help of the answers given by #detunized & #nimblegorilla, I came up with:
"998700"[0..-3].rjust(6, '0').to_sym
to make the first format I described (always with two trailing zeros) equal to the second.

How can I output leading zeros in Ruby?

I'm outputting a set of numbered files from a Ruby script. The numbers come from incrementing a counter, but to make them sort nicely in the directory, I'd like to use leading zeros in the filenames. In other words
file_001...
instead of
file_1
Is there a simple way to add leading zeros when converting a number to a string? (I know I can do "if less than 10.... if less than 100").
Use the % operator with a string:
irb(main):001:0> "%03d" % 5
=> "005"
The left-hand-side is a printf format string, and the right-hand side can be a list of values, so you could do something like:
irb(main):002:0> filename = "%s/%s.%04d.txt" % ["dirname", "filename", 23]
=> "dirname/filename.0023.txt"
Here's a printf format cheat sheet you might find useful in forming your format string. The printf format is originally from the C function printf, but similar formating functions are available in perl, ruby, python, java, php, etc.
If the maximum number of digits in the counter is known (e.g., n = 3 for counters 1..876), you can do
str = "file_" + i.to_s.rjust(n, "0")
Can't you just use string formatting of the value before you concat the filename?
"%03d" % number
Use String#next as the counter.
>> n = "000"
>> 3.times { puts "file_#{n.next!}" }
file_001
file_002
file_003
next is relatively 'clever', meaning you can even go for
>> n = "file_000"
>> 3.times { puts n.next! }
file_001
file_002
file_003
As stated by the other answers, "%03d" % number works pretty well, but it goes against the rubocop ruby style guide:
Favor the use of sprintf and its alias format over the fairly
cryptic String#% method
We can obtain the same result in a more readable way using the following:
format('%03d', number)
filenames = '000'.upto('100').map { |index| "file_#{index}" }
Outputs
[file_000, file_001, file_002, file_003, ..., file_098, file_099, file_100]

Suppressing a trailing "." in numerical output from Mathematica

Is there some straightforward way to ensure that, when converted to strings, approximate numbers (i.e., numbers with the Real head) won't have a trailing "."? I would like it if they were to only have the decimal point in cases where there's actually a displayed fractional part.
The solutions I've found are not robust, and depend on using Precision and Accuracy together NumberForm in an awkward way, or using RealDigits in an even more awkward way.
Thanks in advance.
I've used this in the past when displaying numbers in figures:
Integerise[x_] := If[Round[x] == x, ToString[Round#x] <> ".0", ToString#x]
Just remove <> ".0" if you don't want integers to be displayed with a zero decimal.
Update: As mentioned by dreeves in the comment, ToString will still truncate a number within 0.0001 or so of an integer and display the dot.
A better way to remove the trailing dot is to use the Inputform format for ToString:
NormalNumber[x_] := ToString[x, InputForm]
with a test:
NormalNumber /# {5, 5.5, 123.001, 123.0001}
This could be incorporated into Integerise above to fix the problem noted.
I recommend this:
shownum[x_] := StringReplace[ToString#NumberForm[x, ExponentFunction->(Null&)],
RegularExpression["\\.$"]->""]
It just does a regex search&replace on the trailing ".". If you want "123." to display as "123.0" instead of "123" then just replace that final empty string with ".0".
UPDATE: My original version displayed wrong for numbers that Mathematica by default displays in scientific notation.
I fixed that with NumberForm.
Here's the version I actually use in real life. It allows for optional rounding:
(* Show Number. Convert to string w/ no trailing dot. Round to the nearest r. *)
Unprotect[Round]; Round[x_,0] := x; Protect[Round];
re = RegularExpression;
shn[x_, r_:0] := StringReplace[
ToString#NumberForm[Round[N#x,r], ExponentFunction->(Null&)], re#"\\.$"->""]
I'd probably just post-process the string. It's faster (and way easier) to just check if the last character is "." than to do redundant arithmetic and take into account all the precision settings.
Edit: maybe you know this, but you can do something like this:
userToString[expr_, form___] := ToString[expr,form];
userToString[expr_Real, form___] := removeTrailingDot[ToString[expr,form]];
The functions NumberForm, ScientificForm, EngineeringForm, etc. ... offers the option NumberFormat to format and arrange the mantissa, base and exponent of a number. With
numberTrim[expr_] := NumberForm[expr,
NumberFormat -> (Row[{StringTrim[#1, "."],
If[#3 == "", "", "\[ThinSpace]\[Times]\[ThinSpace]" <> #2^#3]}] &)];
the default Mathematica output is reproduced, but the trailing dot is removed.

Resources