How to format numerical values?

Island/Windows/Oxygene

var d: Double := 123456789.222222222

I’d like to format double to either fixed point or scientific fomat, but none of the following works.

I tried
String.Format("{0, 4: G3}", d);
StringFormatter.Format({0, 4: G3}", d)

Any heads up?

@mh

Use RTL2’s Convert.ToString(), for now.

Oh I see - customized formatting not supported yet on Island. A bit disappointing, but I understand the status quo.

Unfortunately, Convert.ToString doesn’t do the nice formatting work for numerical values.

If I may - I would suggest to add this formatting capability to Island platform.

  • This is advisable, because, Island platform by its native nature, is very good for numerical/scientific computation (i.e., modern language, yet with performance. Much better than Python!). As such, it would be really great to have this formatting capability to output formatted numerical values, as needed in many numerical computation-intensive applications.

Hope this makes sense. @mh

class method Main(args: array of String): Int32;
begin
  // add your own code here
  writeLn('The magic happens here.');
  var d: Double := 123456789.123456789123456789;
  var i: Integer := 123456789;
  writeLn(String.Format("{0,8:F2}", i));
  writeLn(String.Format("{0,8:F2}", d));

end;

Correct, Elements RTL only implements standard {0} format, not customizations, at this time.

Agreed, we should both expand Convert and expand the String.Format() support. What specifically are you missing from Convert?

Thanks, logged as bugs://83871 for String.Format

Hi Marc

Of the utmost need — the capability to format numerical values, based on space-control, and precision control, something like:

String.Format( “Output:{0,10: F2”}, 12345.1234567)

Output: 12345.12

Ok, I was asking because Convert.ToString does provide that:

method ToString(aValue: Double; aDigitsAfterDecimalPoint: Integer := -1; aLocale: Locale := nil): not nullable String;
method ToStringInvariant(aValue: Double; aDigitsAfterDecimalPoint: Integer := -1): not nullable String;

Thank you, but Convert.ToString doesn’t seem to be able to control filler spaces? It only controls precision (i…e, number of digits after decimal point).

Space control is needed to do proper output text alignment.

It indeed does not, currently, yes. I’ll see if we can dd that. That said, if the number of decimal points is known, a simple “.PadStart(” “, x)” on the result should do the trick for now.

Since I don’t work with doubles often myself, what’s the convention here, what does “10:F2” mean? opal to 10 digits left of the “.”, and two significant digits to there right? (I know, I could probably research this myself ;).

What would be, IYO, the bets way to add this to Convert.ToString, a third int parameter that would what _ the digits/padding left of the decimal? or the entire length?

Hi Marc,

Thank you again. .NET standard numeric format string is outlined here.

Basically, String.Format("{0, 10:F2}", 12345.1234567), means:

  • F2: fixed point, with 2 digit after the decimal point

  • 10: means if the converted string has less than 10 chars (including the decimal point and the digits after the decimal points), insert filler spaces from the left side (i.e., right-aligned); if the converted string has more than 10 chars, take the actual chars.

  • -10: means the same as the above, except inserting chars from the right side (i.e., left-aligned)

So, String.Format("{0, 10:F2}", 12345.1234567) would print:
space space 12345.12

String.Format("{0, -10:F2}", 12345.1234567) would print:
12345.12 space space

String.Format("{0, -10:F2}", 1234567890000.1234567) would print:
1234567890000.12

ok, for. now, I;'m amending Convert.ToString as such:


...oxygene
method Convert.ToStringInvariant(aValue: Double; aDigitsAfterDecimalPoint: Integer := -1; aMinLength: Integer := 0): not nullable String;
method Convert.ToString(aValue: Double; aDigitsAfterDecimalPoint: Integer := -1; aMinLength: Integer := 0; aLocale: Locale := nil): not nullable String;

...

  if aMinLength > 0 then
    result := result.PadStart(aMinLength, ' ')
  else if aMinLength < 0 then
    result := result.PadEnd(aMinLength, ' ');

Hi Marc,

That should work. Thank you. Is it possible to internally map String.Format to this new Convert.ToString? I’d like to keep my code “future-proof”.

In the long run, hope we could have a full-fledged String.Format like .NET, as I saw Island potentially is a first-class language for numerical applications.

Yeah, I logged an issue for that, but thats not a one-day fix :wink:

Understand appreciate it. Is it possible to internally map String.Format to this new Convert.ToString? If so, I can keep my code “future-proof”. If not, also fine.

Not easily no. It will eventually use that unwell the hood, but the main (remaining) job will be to extend for String.Format parser to handle the extended {} syntax.