Skip to content

Commit abed746

Browse files
Formatting Tweaks
1 parent 3a3f9e7 commit abed746

3 files changed

Lines changed: 164 additions & 74 deletions

File tree

src/GoogolSharp/Helpers/ArithmonymFormattingUtils.cs

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,49 +24,101 @@ namespace GoogolSharp.Helpers
2424
{
2525
public static class ArithmonymFormattingUtils
2626
{
27-
public static string FormatArithmonymFromLetterF(Float128 letterF, bool isReciprocal, string placeholder = "E", bool showExponentSignIfPositive = true)
27+
public static string FormatArithmonymFromLetterF(
28+
Float128 letterF,
29+
bool isReciprocal,
30+
string placeholder = "E",
31+
bool showExponentSignIfPositive = true)
2832
{
29-
if (letterF < 2) return new Arithmonym(Float128HyperTranscendentals.LetterF(letterF)).ToString();
33+
if (letterF < 2)
34+
return new Arithmonym(Float128HyperTranscendentals.LetterF(letterF)).ToString();
35+
3036
if (letterF < 3)
3137
{
3238
Float128 letterE = Float128PreciseTranscendentals.SafeExp10(
3339
Float128PreciseTranscendentals.SafeExp10(
34-
letterF - 2));
40+
Float128.FusedMultiplyAdd(letterF, 1, -2)));
41+
3542
return FormatArithmonymScientific(letterE, isReciprocal, placeholder, showExponentSignIfPositive);
3643
}
44+
3745
if (letterF < 7)
3846
{
47+
string sign = isReciprocal ? "-" :
48+
showExponentSignIfPositive ? "+" : "";
49+
3950
if (placeholder == "*10^")
40-
return $"10^({(isReciprocal ? "-" : showExponentSignIfPositive ? "+" : "")}{FormatArithmonymFromLetterF(letterF - 1, false, placeholder, showExponentSignIfPositive)})";
41-
return $"{placeholder}{(isReciprocal ? "-" : showExponentSignIfPositive ? "+" : "")}{FormatArithmonymFromLetterF(letterF - 1, false, placeholder, showExponentSignIfPositive)}";
51+
return $"10^({sign}{FormatArithmonymFromLetterF(letterF - 1, false, placeholder, showExponentSignIfPositive)})";
52+
53+
return $"{placeholder}{sign}{FormatArithmonymFromLetterF(letterF - 1, false, placeholder, showExponentSignIfPositive)}";
4254
}
55+
4356
if (letterF < 100000000000000000000.0)
4457
{
4558
Float128 right = Float128.Floor(letterF);
46-
Float128 left = Float128PreciseTranscendentals.SafeExp10(letterF - right);
59+
Float128 left = Float128PreciseTranscendentals.SafeExp10(
60+
Float128.FusedMultiplyAdd(letterF, 1, -right));
61+
62+
// Normalize
4763
if (left < 1)
4864
{
49-
right--;
65+
right -= 1;
5066
left *= 10;
5167
}
52-
if (left > 10)
68+
else if (left >= 10)
5369
{
54-
right++;
70+
right += 1;
5571
left /= 10;
5672
}
57-
return $"{(isReciprocal ? "1 / (" : "")}{left}F+{right}{(isReciprocal ? ")" : "")}";
73+
74+
string leftStr = left.ToString();
75+
76+
return $"{(isReciprocal ? "1 / (" : "")}{leftStr}F+{right}{(isReciprocal ? ")" : "")}";
5877
}
59-
return $"{(isReciprocal ? "1 / " : "")}F+{letterF}";
78+
79+
return $"{(isReciprocal ? "1 / " : "")}F+{letterF.ToString("R", null)}";
6080
}
6181

62-
public static string FormatArithmonymScientific(Float128 letterE, bool isReciprocal, string placeholder = "E", bool showExponentSignIfPositive = true)
82+
83+
public static string FormatArithmonymScientific(
84+
Float128 letterE,
85+
bool isReciprocal,
86+
string placeholder = "E",
87+
bool showExponentSignIfPositive = true)
6388
{
89+
// exponent = floor(letterE)
6490
Float128 exponent = Float128.Floor(letterE);
91+
92+
// significand = 10^(letterE - exponent)
6593
Float128 significand = Float128PreciseTranscendentals.SafeExp10(
66-
letterE - exponent);
67-
return $"{significand}{placeholder}{(isReciprocal ? "-" : showExponentSignIfPositive ? "+" : "")}{(ulong)exponent}";
94+
Float128.FusedMultiplyAdd(letterE, 1, -exponent));
95+
96+
// Normalize significand into [1, 10)
97+
if (significand < 1)
98+
{
99+
significand *= 10;
100+
exponent -= 1;
101+
}
102+
else if (significand > 9.99999)
103+
{
104+
significand = 1;
105+
exponent += 1;
106+
}
107+
else if (significand >= 10)
108+
{
109+
significand /= 10;
110+
exponent += 1;
111+
}
112+
113+
string sig = significand.ToString("F6", null);
114+
115+
string sign = isReciprocal ? "-" :
116+
showExponentSignIfPositive ? "+" : "";
117+
118+
return $"{sig}{placeholder}{sign}{(ulong)exponent}";
68119
}
69120

121+
70122
/// <summary>
71123
/// Formats a Float128 value, rounding to integer if it is very close to an integer (within precision tolerance).
72124
/// This prevents floating-point artifacts like "5.000000000000000000000000025..." from being displayed.

src/GoogolSharp/Modules/FormattingOperations.cs

Lines changed: 91 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using QuadrupleLib.Accelerators;
2222
using Float128 = QuadrupleLib.Float128<QuadrupleLib.Accelerators.DefaultAccelerator>;
2323
using System.Globalization;
24+
using System.Text;
2425

2526
namespace GoogolSharp
2627
{
@@ -65,23 +66,18 @@ private static string ToBinaryString(uint number, int bitWidth = 0)
6566
/// Returns a human-readable string representation of this <see cref="Arithmonym"/>.
6667
/// </summary>
6768
public override string ToString() => ToCommonString();
68-
69-
/// <summary>
70-
/// Returns a human-readable string representation of this <see cref="Arithmonym"/>.
71-
/// </summary>
7269
public string ToLetterString()
7370
{
7471
if (IsNaN(this)) return "NaN";
7572
if (this == PositiveInfinity) return "∞";
7673
if (this == NegativeInfinity) return "-∞";
7774
if (this == Zero) return "0";
7875

79-
// Reconstruct operand in [2, 10)
8076
Float128 value = Operand;
8177

82-
string output = "";
78+
var sb = new StringBuilder();
8379
if (_IsNegative)
84-
output += "-";
80+
sb.Append('-');
8581

8682
string[] letters = ["", "A", "B", "C", "D", "E", "F", "J", "K", "L", "M", "N", "P"];
8783
while (letters.Length < 63)
@@ -90,42 +86,61 @@ public string ToLetterString()
9086
switch (Letter)
9187
{
9288
case 0x01:
93-
output += _IsReciprocal
94-
? 1 / (1 + ((value - 2) / 8))
95-
: 1 + ((value - 2) / 8);
96-
break;
89+
{
90+
// 1 + (value - 2)/8 → FMA(value, 1/8, 1 - 2/8)
91+
Float128 t = Float128.FusedMultiplyAdd(value, Float128.One / 8, 1 - (Float128)2 / 8);
92+
sb.Append(_IsReciprocal ? (1 / t).ToString("R", null) : t.ToString("R", null));
93+
break;
94+
}
95+
9796
case 0x02:
98-
output += _IsReciprocal
99-
? 1 / (2 + ((value - 2) / 4))
100-
: 2 + ((value - 2) / 4);
101-
break;
97+
{
98+
// 2 + (value - 2)/4 → FMA(value, 1/4, 2 - 2/4)
99+
Float128 t = Float128.FusedMultiplyAdd(value, Float128.One / 4, 2 - (Float128)2 / 4);
100+
sb.Append(_IsReciprocal ? (1 / t).ToString("R", null) : t.ToString("R", null));
101+
break;
102+
}
103+
102104
case 0x03:
103-
output += _IsReciprocal
104-
? 1 / (value * 2)
105-
: value * 2;
106-
break;
105+
{
106+
Float128 t = value * 2;
107+
sb.Append(_IsReciprocal ? (1 / t).ToString("R", null) : t.ToString("R", null));
108+
break;
109+
}
110+
107111
case 0x04:
108-
output += _IsReciprocal
109-
? 1 / (value * 10)
110-
: value * 10;
111-
break;
112+
{
113+
Float128 t = value * 10;
114+
sb.Append(_IsReciprocal ? (1 / t).ToString("R", null) : t.ToString("R", null));
115+
break;
116+
}
117+
112118
case 0x05:
113-
output += _IsReciprocal
114-
? Float128PreciseTranscendentals.SafeExp10(-value) : Float128PreciseTranscendentals.SafeExp10(value);
115-
break;
119+
{
120+
Float128 t = _IsReciprocal
121+
? Float128PreciseTranscendentals.SafeExp10(-value)
122+
: Float128PreciseTranscendentals.SafeExp10(value);
123+
124+
sb.Append(t.ToString("R", null));
125+
break;
126+
}
127+
116128
case 0x06:
117-
output += ArithmonymFormattingUtils.FormatArithmonymFromLetterF(Operand, _IsReciprocal);
129+
sb.Append(ArithmonymFormattingUtils.FormatArithmonymFromLetterF(Operand, _IsReciprocal));
118130
break;
131+
119132
default:
120133
if (_IsReciprocal)
121-
output += "1 / ";
122-
output += letters[Letter];
123-
output += value;
134+
sb.Append("1 / ");
135+
sb.Append(letters[Letter]);
136+
sb.Append(value.ToString("R", null));
124137
break;
125138
}
126-
return output;
139+
140+
return sb.ToString();
127141
}
128142

143+
129144
/// <summary>
130145
/// Returns a human-readable string representation of this <see cref="Arithmonym"/>.
131146
/// </summary>
@@ -136,63 +151,79 @@ public string ToCommonString()
136151
if (this == NegativeInfinity) return "-∞";
137152
if (this == Zero) return "0";
138153

139-
// Reconstruct operand in [2, 10)
140154
Float128 value = Operand;
141155

142-
if (Letter == 0x0C) value += 2;
156+
if (Letter == 0x0C)
157+
value += 2;
143158

144-
string output = "";
159+
var sb = new StringBuilder();
145160
if (_IsNegative)
146-
output += "-";
161+
sb.Append('-');
147162

148163
string[] prefixes = ["", "A", "B", "C", "D", "10^", "10^^", "{10,10,", "{10,", "{10,", "{10,10,", "{10,10,10,", "{10,", "X^^", "X^^^", "{X,"];
149164
while (prefixes.Length < 63)
150165
prefixes = [.. prefixes, $"[{prefixes.Length}]"];
166+
151167
string[] suffixes = ["", "", "", "", "", "", "", "}", ",1,2}", ",2,2}", ",2}", "}", "(1)2}", " & 10", " & 10"];
152168
while (suffixes.Length < 63)
153169
suffixes = [.. suffixes, $"[{suffixes.Length}]"];
154170

155171
switch (Letter)
156172
{
157173
case 0x01:
158-
output += _IsReciprocal
159-
? 1 / (1 + ((value - 2) / 8))
160-
: 1 + ((value - 2) / 8);
161-
break;
174+
{
175+
Float128 t = Float128.FusedMultiplyAdd(value, Float128.One / 8, 1 - (Float128)2 / 8);
176+
sb.Append(_IsReciprocal ? (1 / t).ToString("R", null) : t.ToString("R", null));
177+
break;
178+
}
179+
162180
case 0x02:
163-
output += _IsReciprocal
164-
? 1 / (2 + ((value - 2) / 4))
165-
: 2 + ((value - 2) / 4);
166-
break;
181+
{
182+
Float128 t = Float128.FusedMultiplyAdd(value, Float128.One / 4, 2 - (Float128)2 / 4);
183+
sb.Append(_IsReciprocal ? (1 / t).ToString("R", null) : t.ToString("R", null));
184+
break;
185+
}
186+
167187
case 0x03:
168188
{
169-
Float128 result = _IsReciprocal
170-
? 1 / (value * 2)
171-
: value * 2;
172-
output += ArithmonymFormattingUtils.FormatNearInteger(result);
189+
Float128 t = value * 2;
190+
Float128 result = _IsReciprocal ? 1 / t : t;
191+
sb.Append(ArithmonymFormattingUtils.FormatNearInteger(result));
173192
break;
174193
}
194+
175195
case 0x04:
176-
output += _IsReciprocal
177-
? 1 / (value * 10)
178-
: value * 10;
179-
break;
196+
{
197+
Float128 t = value * 10;
198+
sb.Append(_IsReciprocal ? (1 / t).ToString("R", null) : t.ToString("R", null));
199+
break;
200+
}
201+
180202
case 0x05:
181-
output += _IsReciprocal
182-
? Float128PreciseTranscendentals.SafeExp10(-value) : Float128PreciseTranscendentals.SafeExp10(value);
183-
break;
203+
{
204+
Float128 t = _IsReciprocal
205+
? Float128PreciseTranscendentals.SafeExp10(-value)
206+
: Float128PreciseTranscendentals.SafeExp10(value);
207+
208+
sb.Append(t.ToString("R", null));
209+
break;
210+
}
211+
184212
case 0x06:
185-
output += ArithmonymFormattingUtils.FormatArithmonymFromLetterF(Operand, _IsReciprocal, "*10^", false);
213+
sb.Append(ArithmonymFormattingUtils.FormatArithmonymFromLetterF(Operand, _IsReciprocal, "*10^", false));
186214
break;
215+
187216
default:
188217
if (_IsReciprocal)
189-
output += "1 / ";
190-
output += prefixes[Letter];
191-
output += value;
192-
output += suffixes[Letter];
218+
sb.Append("1 / ");
219+
sb.Append(prefixes[Letter]);
220+
sb.Append(value.ToString("R", null));
221+
sb.Append(suffixes[Letter]);
193222
break;
194223
}
195-
return output;
224+
225+
return sb.ToString();
196226
}
227+
197228
}
198229
}

tools/ArithmonymDebug/Program.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using GoogolSharp;
2+
3+
Arithmonym googol = Arithmonym.Pow(10, 100);
4+
Console.WriteLine($"{googol}");
5+
6+
Arithmonym megafugafour = Arithmonym.Pow(4,Arithmonym.Pow(4,Arithmonym.Pow(4, 4)));
7+
Console.WriteLine($"{megafugafour}");

0 commit comments

Comments
 (0)