# Parse floats to a custom numeric format string

I'm working to implement a custom string format. These are the float values to convert into a string:

1,02458
0,4145805
0,06231292
0,04362812
1,16458
1,172608
0,06011338
0,05324263
0,0653288
0,0285034
0,0992517
0,0861678


This is the output I'm getting:

1.02458f
.4145805f
6.231292E-02f
4.362812E-02f
1.16458f
1.172608f
6.011338E-02f
5.324263E-02f
.0653288f
.0285034f
.0992517f
.0861678f


The idea is, if the decimal places are greater than 8, use the scientific notation. If not, remove the left zeros. Now I'm using this code, but I would like to know if there's another more efficient way of doing this but always getting the same output:

Dim numericProvider As New NumberFormatInfo With {
.NumberDecimalSeparator = "."
}

'Get the number of decimal places
Dim stringNum As String = waveDuration.ToString(numericProvider)
Dim decimalPlaces As Integer = 0
If InStr(1, stringNum, ".", CompareMethod.Binary) Then
decimalPlaces = stringNum.Substring(stringNum.IndexOf(".")).Length
End If

'Format String
Dim waveDurationFormat As String
If decimalPlaces > 8 Then
waveDurationFormat = waveDuration.ToString("0.######E+00", numericProvider)
Else
waveDurationFormat = waveDuration.ToString(".#######", numericProvider)
End If


• Not a code review, but of the algorithm you chose: wouldn't it make more sense to use scientific notation when there are many leading zeros, rather than many significant fractional digits? Or more generally, when the number of total digits is 2 or 3 greater than the number of significant digits, so you'd also scientific for 120000.0 => 1.2E5f. This would avoid lengthening numbers, and also choose the same format for two small numbers of the same order of magnitude. (e.g. 0.01 and 0.01234567 would both stay as-is, so they visually line up for humans. Not so for large numbers though.) Mar 16, 2022 at 18:55
• Hello, yes, you're right. But the tool, I'm working on, is for a custom-made engine for a video game, and for some unknown reason uses this format. But yeah, it would make more sense of doing it with this other way. Mar 18, 2022 at 23:32
• Does it not accept numbers like 1.2E5f, but does accept 1.2345E5f? Or it prints numbers that way and you're trying to exactly match its output? Mar 18, 2022 at 23:52
• Well, with this code I've got the same output, the original exporter also prints the numbers in this way. Mar 22, 2022 at 9:16
• Ok, so you are just trying to match its exact output for some reason. (Perhaps so text diffs work better). Not because something else would reject this input if you made saner choices. Mar 22, 2022 at 17:30

Welcome to Code Review! Nice first question.

Instead of using Instr() to check if stringNum contains a . you can just use String.IndexOf() and check if the result is > -1 which means the string representation of waveDuration contains a ..

If IndexOf() returns a value greater than -1 we can just check if stringNum.Length - stringNum.IndexOf(".") > 8. This has the advantage that the code won't create a new string each time it is called because we don't need to call Substring() anymore.

I would place this whole stuff inside an Extension method having an optional parameter stating the numbers of decimalplaces like so

Imports System.Globalization
Imports System.Runtime.CompilerServices
Module StringExtensions
Dim numericProvider As New NumberFormatInfo With {.NumberDecimalSeparator = "."}

<Extension()>
Public Function ToCustomString(ByVal value As Single, Optional scientificNotationDecimalPlaces As Integer = 8) As String
If scientificNotationDecimalPlaces < 0 Then
Throw New ArgumentOutOfRangeException(NameOf(scientificNotationDecimalPlaces))
End If

Dim stringValue As String = value.ToString(numericProvider)

Dim decimalPointIndex As Integer = stringValue.IndexOf(".")

If decimalPointIndex > -1 AndAlso stringValue.Length - decimalPointIndex > scientificNotationDecimalPlaces Then
Return value.ToString("0.######E+00", numericProvider)
End If

Return value.ToString(".#######", numericProvider)

End Function
End Module


You could then call it like so

ListBox3.Items.Add(waveDuration.ToCustomString())


or e.g if you want to have the sientific notation only if the decimal places are greater than 5 like so

ListBox3.Items.Add(waveDuration.ToCustomString(5))