Last active
January 15, 2022 19:06
-
-
Save bboyle1234/df47f661b531efd7386f0dbcdfbeee6f to your computer and use it in GitHub Desktop.
Humanizes numbers. Makes them human-readable
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using static System.Math; | |
namespace Foo { | |
public static class DoubleExtensions { | |
public static double RoundToSignificantFigures(this double value, int numSignificantFigures) { | |
if (value == 0) return 0.0; | |
var scale = Pow(10, Floor(Log10(Abs(value))) + 1); | |
// Perform the last step using decimals to prevent double-arithmetic re-introducing tiny errors (and more figures to the result) | |
return (double)((decimal)scale * (decimal)Math.Round(value / scale, numSignificantFigures)); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using static System.Math; | |
namespace Foo { | |
public static class HumanReadableDoubles { | |
// Created with thanks to http://stackoverflow.com/questions/16083666/make-big-and-small-numbers-human-readable/16091580#16091580 | |
static readonly string[] humanReadableSuffixes = { "f", "a", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P", "E" }; | |
public static string ToHumanReadable(this double value, int numSignificantDigits) { | |
// Deal with special values | |
if (double.IsInfinity(value) || double.IsNaN(value) || value == 0 || numSignificantDigits <= 0) | |
return value.ToString(); | |
// We deal only with positive values in the code below | |
var isNegative = Sign(value) < 0; | |
value = Abs(value); | |
// Calculate the exponent as a multiple of 3, ie -6, -3, 0, 3, 6, etc | |
var exponent = (int)Floor(Log10(value) / 3) * 3; | |
// Find the correct suffix for the exponent, or fall back to scientific notation | |
var indexOfSuffix = exponent / 3 + 6; | |
var suffix = indexOfSuffix >= 0 && indexOfSuffix < humanReadableSuffixes.Length | |
? humanReadableSuffixes[indexOfSuffix] | |
: "·10^" + exponent; | |
// Scale the value to the exponent, then format it to the correct number of significant digits and add the suffix | |
value = value * Pow(10, -exponent); | |
var numIntegerDigits = (int)Floor(Log(value, 10)) + 1; | |
var numFractionalDigits = Min(numSignificantDigits - numIntegerDigits, 15); | |
var format = $"{new string('0', numIntegerDigits)}.{new string('0', numFractionalDigits)}"; | |
var result = value.ToString(format) + suffix; | |
// Handle negatives | |
if (isNegative) | |
result = "-" + result; | |
return result; | |
} | |
public static double ParseHumanReadableDouble(this string expression) { | |
var multiplier = 1.0; | |
if (expression.Contains("·10^")) { | |
var indexOfCaret = expression.LastIndexOf('^'); | |
multiplier = Pow(10, int.Parse(expression.Substring(indexOfCaret + 1))); | |
expression = expression.Substring(0, indexOfCaret - 3); | |
} else { | |
var suffix = humanReadableSuffixes.SingleOrDefault(s => s.Length > 0 && expression.EndsWith(s, StringComparison.InvariantCulture)) ?? ""; | |
var suffixIndex = humanReadableSuffixes.IndexOf(suffix); | |
multiplier = Pow(10, 3 * (suffixIndex - 6)); | |
expression = expression.Replace(suffix, string.Empty); | |
} | |
return double.Parse(expression) * multiplier; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sorry to dump more code at you, but how about these numeric manipulation functions:
Fore me
WrapAround
andClampMinMax
are used all the time.Chi
not so often. Examples would be getting angle results between -180 and +180. or 0 to 360 for usage inSin()
orCos()
in order to maintain precision. Try to see thatSin(1) != Sin(1+2*Math.PI)
. They differ by some10^-16
. But as the angles go up that error accumulates rapidly.