I am working on a system that needs to accept and display complex fractions. The code for accepting fractions and turning them in to a double works, but when I want to display that value, I need to convert back to a fractional representation.
EDIT: I have fixed the overflow problem, but that didnt solve fractions like 1/3 or 5/6. SO I have devised a very hacky way to do this. I have code which generates the decimal representation of every fraction 0->64 over 1->64, and saves the most simplified form. This way, I can iterate through the list and find the closest fraction, and simply display that. Will post code once I have some.
I have code now that works for the vast majority of numbers, but occasionally I will get a tiny fraction like 1/321. This gets converted to a double, but cannot be converted back, because in my approach, the numerator causes an integer overflow.
Here is my code, I'm wondering if there is a better approach, or if there is someway to safely convert these to longs without losing the precision needed for a correct result:
public static String DecimalToFraction(double dec)
{
string str = dec.ToString();
if (str.Contains('.'))
{
String[] parts = str.Split('.');
long whole = long.Parse(parts[0]);
long numerator = long.Parse(parts[1]);
long denominator = (long)Math.Pow(10, parts[1].Length);
long divisor = GCD(numerator, denominator);
long num = numerator / divisor;
long den = denominator / divisor;
String fraction = num + "/" + den;
if (whole > 0)
{
return whole + " " + fraction;
}
else
{
return fraction;
}
}
else
{
return str;
}
}
public static long GCD(long a, long b)
{
return b == 0 ? a : GCD(b, a % b);
}
Recently I had to code a similar scenario. In my case, converting from decimal to rational number had to be a little more mathematically correct so I ended up implementing a Continued Fraction algorithm.
Although it is tailored made to my concrete implementation of RationalNumber, you should get the idea. It's a relatively simple algorithm that works reasonably well for any rational number approximation. Note that the implementation will give you the closest approximation with the required precision.
/// <summary>
/// Represents a rational number with 64-bit signed integer numerator and denominator.
/// </summary>
[Serializable]
public struct RationalNumber : IComparable, IFormattable, IConvertible, IComparable<RationalNumber>, IEquatable<RationalNumber>
{
private const int MAXITERATIONCOUNT = 20;
public RationalNumber(long number) {...}
public RationalNumber(long numerator, long denominator) {...}
public RationalNumber(RationalNumber numerator, RationalNumer denominator) {...}
...
/// <summary>
/// Defines an implicit conversion of a 64-bit signed integer to a rational number.
/// </summary>
/// <param name="value">The value to convert to a rational number.</param>
/// <returns>A rational number that contains the value of the value parameter as its numerator and 1 as its denominator.</returns>
public static implicit operator RationalNumber(long value)
{
return new RationalNumber(value);
}
/// <summary>
/// Defines an explicit conversion of a rational number to a double-precision floating-point number.
/// </summary>
/// <param name="value">The value to convert to a double-precision floating-point number.</param>
/// <returns>A double-precision floating-point number that contains the resulting value of dividing the rational number's numerator by it's denominator.</returns>
public static explicit operator double(RationalNumber value)
{
return (double)value.numerator / value.Denominator;
}
...
/// <summary>
/// Adds two rational numbers.
/// </summary>
/// <param name="left">The first value to add.</param>
/// <param name="right">The second value to add.</param>
/// <returns>The sum of left and right.</returns>
public static RationalNumber operator +(RationalNumber left, RationalNumber right)
{
//First we try directly adding in a checked context. If an overflow occurs we use the least common multiple and return the result. If it overflows again, it
//will be up to the consumer to decide what he will do with it.
//Cost penalty should be minimal as adding numbers that cause an overflow should be very rare.
RationalNumber result;
try
{
long numerator = checked(left.numerator * right.Denominator + right.numerator * left.Denominator);
long denominator = checked(left.Denominator * right.Denominator);
result = new RationalNumber(numerator,denominator);
}
catch (OverflowException)
{
long lcm = RationalNumber.getLeastCommonMultiple(left.Denominator, right.Denominator);
result = new RationalNumber(left.numerator * (lcm / left.Denominator) + right.numerator * (lcm / right.Denominator), lcm);
}
return result;
}
private static long getGreatestCommonDivisor(long i1, long i2)
{
Debug.Assert(i1 != 0 || i2 != 0, "Whoops!. Both arguments are 0, this should not happen.");
//Division based algorithm
long i = Math.Abs(i1);
long j = Math.Abs(i2);
long t;
while (j != 0)
{
t = j;
j = i % j;
i = t;
}
return i;
}
private static long getLeastCommonMultiple(long i1, long i2)
{
if (i1 == 0 && i2 == 0)
return 0;
long lcm = i1 / getGreatestCommonDivisor(i1, i2) * i2;
return lcm < 0 ? -lcm : lcm;
}
...
/// <summary>
/// Returns the nearest rational number approximation to a double-precision floating-point number with a specified precision.
/// </summary>
/// <param name="target">Target value of the approximation.</param>
/// <param name="precision">Minimum precision of the approximation.</param>
/// <returns>Nearest rational number with, at least, the required precision.</returns>
/// <exception cref="System.ArgumentException">Can not find a rational number approximation with specified precision.</exception>
/// <exception cref="System.OverflowException">target is larger than Mathematics.RationalNumber.MaxValue or smaller than Mathematics.RationalNumber.MinValue.</exception>
/// <remarks>It is important to clarify that the method returns the first rational number found that complies with the specified precision.
/// The method is not required to return an exact rational number approximation even if such number exists.
/// The returned rational number will always be in coprime form.</remarks>
public static RationalNumber GetNearestRationalNumber(double target, double precision)
{
//Continued fraction algorithm: http://en.wikipedia.org/wiki/Continued_fraction
//Implemented recursively. Problem is figuring out when precision is met without unwinding each solution. Haven't figured out how to do that.
//Current implementation evaluates a Rational approximation for increasing algorithm depths until precision criteria is met or maximum depth is reached (MAXITERATIONCOUNT)
//Efficiency is probably improvable but this method will not be used in any performance critical code. No use in optimizing it unless there is a good reason.
//Current implementation works reasonably well.
RationalNumber nearestRational = RationalNumber.zero;
int steps = 0;
while (Math.Abs(target - (double)nearestRational) > precision)
{
if (steps > MAXITERATIONCOUNT)
throw new ArgumentException(Strings.RationalMaximumIterationsExceptionMessage, "precision");
nearestRational = getNearestRationalNumber(target, 0, steps++);
}
return nearestRational;
}
private static RationalNumber getNearestRationalNumber(double number, int currentStep, int maximumSteps)
{
long integerPart;
integerPart = checked((long)number);
double fractionalPart = number - integerPart;
while (currentStep < maximumSteps && fractionalPart != 0)
{
return integerPart + new RationalNumber(1, getNearestRationalNumber(1 / fractionalPart, ++currentStep, maximumSteps));
}
return new RationalNumber(integerPart);
}
}
UPDATE: Whoops, forgot to include the operator + code. Fixed it.
You could use BigRational, which Microsoft released under their BCL project on codeplex. It supports arbitrarily large rational numbers, and actually stores it internally as a ratio. The nice thing is that you can treat it largely as a normal numeric type, since all of the operators are overloaded for you.
Interestingly, it lacks a way to print the number as a decimal. I wrote some code that did this, though, in a previous answer of mine. However, there are no guarantees on its performance or quality (I barely remember writing it).
Keep the number as a fraction:
struct Fraction
{
private int _numerator;
private int _denominator;
public int Numerator { get { return _numerator; } }
public int Denominator { get { return _denominator; } }
public double Value { get { return ((double) Numerator)/Denominator; } }
public Fraction( int n, int d )
{
// move negative to numerator.
if( d < 0 )
{
_numerator = -n;
_denominator = -d;
}
else if( d > 0 )
{
_numerator = n;
_denominator = d;
}
else
throw new NumberFormatException( "Denominator cannot be 0" );
}
public void ToString()
{
string ret = "";
int whole = Numerator / Denominator;
if( whole != 0 )
ret += whole + " ";
ret += Math.Abs(Numerator % Denominator) + "/" + Denominator;
return ret;
}
}
Please check these 2 methods:
/// <summary>
/// Converts Decimals into Fractions.
/// </summary>
/// <param name="value">Decimal value</param>
/// <returns>Fraction in string type</returns>
public string DecimalToFraction(double value)
{
string result;
double numerator, realValue = value;
int num, den, decimals, length;
num = (int)value;
value = value - num;
value = Math.Round(value, 5);
length = value.ToString().Length;
decimals = length - 2;
numerator = value;
for (int i = 0; i < decimals; i++)
{
if (realValue < 1)
{
numerator = numerator * 10;
}
else
{
realValue = realValue * 10;
numerator = realValue;
}
}
den = length - 2;
string ten = "1";
for (int i = 0; i < den; i++)
{
ten = ten + "0";
}
den = int.Parse(ten);
num = (int)numerator;
result = SimplifiedFractions(num, den);
return result;
}
/// <summary>
/// Converts Fractions into Simplest form.
/// </summary>
/// <param name="num">Numerator</param>
/// <param name="den">Denominator</param>
/// <returns>Simplest Fractions in string type</returns>
string SimplifiedFractions(int num, int den)
{
int remNum, remDen, counter;
if (num > den)
{
counter = den;
}
else
{
counter = num;
}
for (int i = 2; i <= counter; i++)
{
remNum = num % i;
if (remNum == 0)
{
remDen = den % i;
if (remDen == 0)
{
num = num / i;
den = den / i;
i--;
}
}
}
return num.ToString() + "/" + den.ToString();
}
}
How can I do this elegantly with C#?
For example, a number can be between 1 and 100.
I know a simple if (x >= 1 && x <= 100) would suffice; but with a lot of syntax sugar and new features constantly added to C#/.Net this question is about more idiomatic (one can all it elegance) ways to write that.
Performance is not a concern, but please add performance note to solutions that are not O(1) as people may copy-paste the suggestions.
There are a lot of options:
int x = 30;
if (Enumerable.Range(1,100).Contains(x)) //true
And indeed basic if more elegantly can be written with reversing order in the first check:
if (1 <= x && x <= 100) //true
Also, check out this SO post for regex options.
Notes:
LINQ solution is strictly for style points - since Contains iterates over all items its complexity is O(range_size) and not O(1) normally expected from a range check.
More generic version for other ranges (notice that second argument is count, not end):
if (Enumerable.Range(start, end - start + 1).Contains(x)
There is temptation to write if solution without && like 1 <= x <= 100 - that look really elegant, but in C# leads to a syntax error "Operator '<=' cannot be applied to operands of type 'bool' and 'int'"
In production code I would simply write
1 <= x && x <= 100
This is easy to understand and very readable.
Starting with C#9.0 we can write
x is >= 1 and <= 100
Note that we must write x only once. is introduces a pattern matching expression where and is part of the pattern.
&& would require us to repeat x is as in x is >= 1 && x is <= 100
Here is a clever method that reduces the number of comparisons from two to one by using some math. There is not necessarily a performance advantage in doing so, but it is elegant. The idea is that one of the two factors becomes negative if the number lies outside of the range and zero if the number is equal to one of the bounds:
If the bounds are inclusive:
(x - 1) * (100 - x) >= 0
or
(x - min) * (max - x) >= 0
If the bounds are exclusive:
(x - 1) * (100 - x) > 0
or
(x - min) * (max - x) > 0
Do you mean?
if(number >= 1 && number <= 100)
or
bool TestRange (int numberToCheck, int bottom, int top)
{
return (numberToCheck >= bottom && numberToCheck <= top);
}
Just to add to the noise here, you could create an extension method:
public static bool IsWithin(this int value, int minimum, int maximum)
{
return value >= minimum && value <= maximum;
}
Which would let you do something like...
int val = 15;
bool foo = val.IsWithin(5,20);
That being said, this seems like a silly thing to do when the check itself is only one line.
As others said, use a simple if.
You should think about the ordering.
e.g
1 <= x && x <= 100
is easier to read than
x >= 1 && x <= 100
I propose this:
public static bool IsWithin<T>(this T value, T minimum, T maximum) where T : IComparable<T> {
if (value.CompareTo(minimum) < 0)
return false;
if (value.CompareTo(maximum) > 0)
return false;
return true;
}
Examples:
45.IsWithin(32, 89)
true
87.2.IsWithin(87.1, 87.15)
false
87.2.IsWithin(87.1, 87.25)
true
and of course with variables:
myvalue.IsWithin(min, max)
It's easy to read (close to human language) and works with any comparable type (integer, double, custom types...).
Having code easy to read is important because the developer will not waste "brain cycles" to understand it. In long coding sessions wasted brain cycles make developer tired earlier and prone to bug.
With a bit of extension method abuse, we can get the following "elegant" solution:
using System;
namespace Elegant {
public class Range {
public int Lower { get; set; }
public int Upper { get; set; }
}
public static class Ext {
public static Range To(this int lower, int upper) {
return new Range { Lower = lower, Upper = upper };
}
public static bool In(this int n, Range r) {
return n >= r.Lower && n <= r.Upper;
}
}
class Program {
static void Main() {
int x = 55;
if (x.In(1.To(100)))
Console.WriteLine("it's in range! elegantly!");
}
}
}
If this is incidental, a simple if is all you need. If this happens in many places, you might want to consider these two:
PostSharp. Decorate methods with attributes that 'inject' code into the method after compilation. I don't know for sure, but I can imagine it can be used for this.
Something like:
[Between("parameter", 0, 100)]
public void Foo(int parameter)
{
}
Code contracts. Has the advantage that the constraints can be checked at compile time, by static verification of your code and the places that use your code.
if (value > 1 && value < 100)
{
// do work
}
else
{
// handle outside of range logic
}
EDIT: New Answer provided.
I was just starting out using C# when I wrote the first answer to this question, and in hindsight I now realize that my "solution" was / is naive and inefficient.
My original answer:
I'd go with the more simple version:
`if(Enumerable.Range(1,100).Contains(intInQuestion)) { ...DoStuff; }`
A Better Way
As I haven't seen any other solution that is more efficient (according to my tests at least), I'll give it another go.
New and better way that also works with negative ranges:
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
This can be used with both positive and negative ranges and defaults to a range of
1..100 (inclusive) and uses x as the number to check followed by an optional range defined by min and max.
Adding Examples For Good Measure
Example 1:
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
Console.WriteLine(inRange(25));
Console.WriteLine(inRange(1));
Console.WriteLine(inRange(100));
Console.WriteLine(inRange(25, 30, 150));
Console.WriteLine(inRange(-25, -50, 0));
Returns:
True
True
True
False
True
Example 2:
Using a list of 100000 random ints between 1 and 150
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
// Generate 100000 ints between 1 and 150
var intsToCheck = new List<int>();
var randGen = new Random();
for(int i = 0; i < 100000; ++i){
intsToCheck.Add(randGen.Next(150) + 1);
}
var counter = 0;
foreach(int n in intsToCheck) {
if(inRange(n)) ++counter;
}
Console.WriteLine("{0} ints found in range 1..100", counter);
Returns:
66660 ints found in range 1..100
Execution Time: 0.016 second(s)
Using an && expression to join two comparisons is simply the most elegant way to do this. If you try using fancy extension methods and such, you run into the question of whether to include the upper bound, the lower bound, or both. Once you start adding additional variables or changing the extension names to indicate what is included, your code becomes longer and harder to read (for the vast majority of programmers). Furthermore, tools like Resharper will warn you if your comparison doesn't make sense (number > 100 && number < 1), which they won't do if you use a method ('i.IsBetween(100, 1)').
The only other comment I'd make is that if you're checking inputs with the intention to throw an exception, you should consider using code contracts:
Contract.Requires(number > 1 && number < 100)
This is more elegant than if(...) throw new Exception(...), and you could even get compile-time warnings if someone tries to call your method without ensuring that the number is in bounds first.
static class ExtensionMethods
{
internal static bool IsBetween(this double number,double bound1, double bound2)
{
return Math.Min(bound1, bound2) <= number && number <= Math.Max(bound2, bound1);
}
internal static bool IsBetween(this int number, double bound1, double bound2)
{
return Math.Min(bound1, bound2) <= number && number <= Math.Max(bound2, bound1);
}
}
Usage
double numberToBeChecked = 7;
var result = numberToBeChecked.IsBetween(100,122);
var result = 5.IsBetween(100,120);
var result = 8.0.IsBetween(1.2,9.6);
These are some Extension methods that can help
public static bool IsInRange<T>(this T value, T min, T max)
where T : System.IComparable<T>
{
return value.IsGreaterThenOrEqualTo(min) && value.IsLessThenOrEqualTo(max);
}
public static bool IsLessThenOrEqualTo<T>(this T value, T other)
where T : System.IComparable<T>
{
var result = value.CompareTo(other);
return result == -1 || result == 0;
}
public static bool IsGreaterThenOrEqualTo<T>(this T value, T other)
where T : System.IComparable<T>
{
var result = value.CompareTo(other);
return result == 1 || result == 0;
}
Ok I'll play along. So many answers already but maybe still room for some other novelties:
(obviously don't actually use these)
var num = 7;
const int min = 5;
const int max = 10;
var inRange = Math.Clamp(num, min, max) == num;
Or
var num = 7;
const int min = 5;
const int max = 10;
var inRange = num switch { < min => false, > max => false, _ => true };
Or
var num = 7;
const int min = 5;
const int max = 10;
var inRange = num is >= min and <= max;
OK maybe you could use that last one.
OK one more
var num = 7;
const int min = 5;
const int max = 10;
var inRange = Enumerable.Range(min, max-min).Contains(num);
In C, if time efficiency is crucial and integer overflows will wrap, one could do if ((unsigned)(value-min) <= (max-min)) .... If 'max' and 'min' are independent variables, the extra subtraction for (max-min) will waste time, but if that expression can be precomputed at compile time, or if it can be computed once at run-time to test many numbers against the same range, the above expression may be computed efficiently even in the case where the value is within range (if a large fraction of values will be below the valid range, it may be faster to use if ((value >= min) && (value <= max)) ... because it will exit early if value is less than min).
Before using an implementation like that, though, benchmark one one's target machine. On some processors, the two-part expression may be faster in all cases since the two comparisons may be done independently whereas in the subtract-and-compare method the subtraction has to complete before the compare can execute.
If you want to write more code than a simple if, maybe you can:
Create a Extension Method called IsBetween
public static class NumberExtensionMethods
{
public static bool IsBetween(this long value, long Min, long Max)
{
// return (value >= Min && value <= Max);
if (value >= Min && value <= Max) return true;
else return false;
}
}
...
// Checks if this number is between 1 and 100.
long MyNumber = 99;
MessageBox.Show(MyNumber.IsBetween(1, 100).ToString());
Addendum: it's worth noting that in practice you very rarely "just check for equality" (or <, >) in a codebase. (Other than in the most trivial situations.) Purely as an example, any game programmer would use categories something like the following in every project, as a basic matter. Note that in this example it (happens to be) using a function (Mathf.Approximately) which is built in to that environment; in practice you typically have to carefully develop your own concepts of what comparisons means for computer representations of real numbers, for the type of situation you are engineering. (Don't even mention that if you're doing something like, perhaps a controller, a PID controller or the like, the whole issue becomes central and very difficult, it becomes the nature of the project.) BY no means is the OP question here a trivial or unimportant question.
private bool FloatLessThan(float a, float b)
{
if ( Mathf.Approximately(a,b) ) return false;
if (a<b) return true;
return false;
}
private bool FloatLessThanZero(float a)
{
if ( Mathf.Approximately(a,0f) ) return false;
if (a<0f) return true;
return false;
}
private bool FloatLessThanOrEqualToZero(float a)
{
if ( Mathf.Approximately(a,0f) ) return true;
if (a<0f) return true;
return false;
}
Cause all the other answer are not invented by me, here just my implementation:
public enum Range
{
/// <summary>
/// A range that contains all values greater than start and less than end.
/// </summary>
Open,
/// <summary>
/// A range that contains all values greater than or equal to start and less than or equal to end.
/// </summary>
Closed,
/// <summary>
/// A range that contains all values greater than or equal to start and less than end.
/// </summary>
OpenClosed,
/// <summary>
/// A range that contains all values greater than start and less than or equal to end.
/// </summary>
ClosedOpen
}
public static class RangeExtensions
{
/// <summary>
/// Checks if a value is within a range that contains all values greater than start and less than or equal to end.
/// </summary>
/// <param name="value">The value that should be checked.</param>
/// <param name="start">The first value of the range to be checked.</param>
/// <param name="end">The last value of the range to be checked.</param>
/// <returns><c>True</c> if the value is greater than start and less than or equal to end, otherwise <c>false</c>.</returns>
public static bool IsWithin<T>(this T value, T start, T end) where T : IComparable<T>
{
return IsWithin(value, start, end, Range.ClosedOpen);
}
/// <summary>
/// Checks if a value is within the given range.
/// </summary>
/// <param name="value">The value that should be checked.</param>
/// <param name="start">The first value of the range to be checked.</param>
/// <param name="end">The last value of the range to be checked.</param>
/// <param name="range">The kind of range that should be checked. Depending on the given kind of range the start end end value are either inclusive or exclusive.</param>
/// <returns><c>True</c> if the value is within the given range, otherwise <c>false</c>.</returns>
public static bool IsWithin<T>(this T value, T start, T end, Range range) where T : IComparable<T>
{
if (value == null)
throw new ArgumentNullException(nameof(value));
if (start == null)
throw new ArgumentNullException(nameof(start));
if (end == null)
throw new ArgumentNullException(nameof(end));
switch (range)
{
case Range.Open:
return value.CompareTo(start) > 0
&& value.CompareTo(end) < 0;
case Range.Closed:
return value.CompareTo(start) >= 0
&& value.CompareTo(end) <= 0;
case Range.OpenClosed:
return value.CompareTo(start) > 0
&& value.CompareTo(end) <= 0;
case Range.ClosedOpen:
return value.CompareTo(start) >= 0
&& value.CompareTo(end) < 0;
default:
throw new ArgumentException($"Unknown parameter value {range}.", nameof(range));
}
}
}
You can then use it like this:
var value = 5;
var start = 1;
var end = 10;
var result = value.IsWithin(start, end, Range.Closed);
You can use pattern matching to achieve this in the most elegant way:
int i = 5;
if(i is (>0 and <=10))
{
}
A new twist on an old favorite:
public bool IsWithinRange(int number, int topOfRange, int bottomOfRange, bool includeBoundaries) {
if (includeBoundaries)
return number <= topOfRange && number >= bottomOfRange;
return number < topOfRange && number > bottomOfRange;
}
How about something like this?
if (theNumber.isBetween(low, high, IntEx.Bounds.INCLUSIVE_INCLUSIVE))
{
}
with the extension method as follows (tested):
public static class IntEx
{
public enum Bounds
{
INCLUSIVE_INCLUSIVE,
INCLUSIVE_EXCLUSIVE,
EXCLUSIVE_INCLUSIVE,
EXCLUSIVE_EXCLUSIVE
}
public static bool isBetween(this int theNumber, int low, int high, Bounds boundDef)
{
bool result;
switch (boundDef)
{
case Bounds.INCLUSIVE_INCLUSIVE:
result = ((low <= theNumber) && (theNumber <= high));
break;
case Bounds.INCLUSIVE_EXCLUSIVE:
result = ((low <= theNumber) && (theNumber < high));
break;
case Bounds.EXCLUSIVE_INCLUSIVE:
result = ((low < theNumber) && (theNumber <= high));
break;
case Bounds.EXCLUSIVE_EXCLUSIVE:
result = ((low < theNumber) && (theNumber < high));
break;
default:
throw new System.ArgumentException("Invalid boundary definition argument");
}
return result;
}
}
I would do a Range object, something like this:
public class Range<T> where T : IComparable
{
public T InferiorBoundary{get;private set;}
public T SuperiorBoundary{get;private set;}
public Range(T inferiorBoundary, T superiorBoundary)
{
InferiorBoundary = inferiorBoundary;
SuperiorBoundary = superiorBoundary;
}
public bool IsWithinBoundaries(T value){
return InferiorBoundary.CompareTo(value) > 0 && SuperiorBoundary.CompareTo(value) < 0;
}
}
Then you use it this way:
Range<int> myRange = new Range<int>(1,999);
bool isWithinRange = myRange.IsWithinBoundaries(3);
That way you can reuse it for another type.
When checking if a "Number" is in a range you have to be clear in what you mean, and what does two numbers are equal mean? In general you should wrap all floating point numbers in what is called a 'epsilon ball' this is done by picking some small value and saying if two values are this close they are the same thing.
private double _epsilon = 10E-9;
/// <summary>
/// Checks if the distance between two doubles is within an epsilon.
/// In general this should be used for determining equality between doubles.
/// </summary>
/// <param name="x0">The orgin of intrest</param>
/// <param name="x"> The point of intrest</param>
/// <param name="epsilon">The minimum distance between the points</param>
/// <returns>Returns true iff x in (x0-epsilon, x0+epsilon)</returns>
public static bool IsInNeghborhood(double x0, double x, double epsilon) => Abs(x0 - x) < epsilon;
public static bool AreEqual(double v0, double v1) => IsInNeghborhood(v0, v1, _epsilon);
With these two helpers in place and assuming that if any number can be cast as a double without the required accuracy. All you will need now is an enum and another method
public enum BoundType
{
Open,
Closed,
OpenClosed,
ClosedOpen
}
The other method follows:
public static bool InRange(double value, double upperBound, double lowerBound, BoundType bound = BoundType.Open)
{
bool inside = value < upperBound && value > lowerBound;
switch (bound)
{
case BoundType.Open:
return inside;
case BoundType.Closed:
return inside || AreEqual(value, upperBound) || AreEqual(value, lowerBound);
case BoundType.OpenClosed:
return inside || AreEqual(value, upperBound);
case BoundType.ClosedOpen:
return inside || AreEqual(value, lowerBound);
default:
throw new System.NotImplementedException("You forgot to do something");
}
}
Now this may be far more than what you wanted, but it keeps you from dealing with rounding all the time and trying to remember if a value has been rounded and to what place. If you need to you can easily extend this to work with any epsilon and to allow your epsilon to change.
Elegant because it doesn't require you to determine which of the two boundary values is greater first. It also contains no branches.
public static bool InRange(float val, float a, float b)
{
// Determine if val lies between a and b without first asking which is larger (a or b)
return ( a <= val & val < b ) | ( b <= val & val < a );
}
If you are concerned with the comment by #Daap on the accepted answer and can only pass the value once, you could try one of the following
bool TestRangeDistance (int numberToCheck, int bottom, int distance)
{
return (numberToCheck >= bottom && numberToCheck <= bottom+distance);
}
//var t = TestRangeDistance(10, somelist.Count()-5, 10);
or
bool TestRangeMargin (int numberToCheck, int target, int margin)
{
return (numberToCheck >= target-margin && numberToCheck <= target+margin);
}
//var t = TestRangeMargin(10, somelist.Count(), 5);
Regarding elegance, the closest thing to the mathematical notation (a <= x <= b) slightly improves readability:
public static bool IsBetween(this int value, int min, int max)
{
return min <= value && value <= max;
}
For further illustration:
public static bool IsOutside(this int value, int min, int max)
{
return value < min || max < value;
}
Using the built in Range struct (C# 8+), we can create an extension method to check if an Index is within the original range.
public static bool IsInRangeOf(this Range range, Index index)
{
return index.Value >= range.Start.Value && index.Value < range.End.Value;
}
Since Index overrides the implicit operator, we can pass an int instead of an Index struct.
var range = new Range(1, 10);
var isInRange = range.IsInRangeOf(1); // true, 1..10 is inclusive min range index(1)
var isInRange = range.IsInRangeOf(10); // false, 1..10 exclusive on max range index (10).
var isInRange = range.IsInRangeOf(100); // false
I was looking for an elegant way to do it where the bounds might be switched (ie. not sure which order the values are in).
This will only work on newer versions of C# where the ?: exists
bool ValueWithinBounds(float val, float bounds1, float bounds2)
{
return bounds1 >= bounds2 ?
val <= bounds1 && val >= bounds2 :
val <= bounds2 && val >= bounds1;
}
Obviously you could change the = signs in there for your purposes. Could get fancy with type casting too. I just needed a float return within bounds (or equal to)
I don't know but i use this method:
public static Boolean isInRange(this Decimal dec, Decimal min, Decimal max, bool includesMin = true, bool includesMax = true ) {
return (includesMin ? (dec >= min) : (dec > min)) && (includesMax ? (dec <= max) : (dec < max));
}
And this is the way I can use it:
[TestMethod]
public void IsIntoTheRange()
{
decimal dec = 54;
Boolean result = false;
result = dec.isInRange(50, 60); //result = True
Assert.IsTrue(result);
result = dec.isInRange(55, 60); //result = False
Assert.IsFalse(result);
result = dec.isInRange(54, 60); //result = True
Assert.IsTrue(result);
result = dec.isInRange(54, 60, false); //result = False
Assert.IsFalse(result);
result = dec.isInRange(32, 54, false, false);//result = False
Assert.IsFalse(result);
result = dec.isInRange(32, 54, false);//result = True
Assert.IsTrue(result);
}
If it's to validate method parameters, none of the solutions throw ArgumentOutOfRangeException and allow easy/proper configuration of inclusive/exclusive min/max values.
Use like this
public void Start(int pos)
{
pos.CheckRange(nameof(pos), min: 0);
if (pos.IsInRange(max: 100, maxInclusive: false))
{
// ...
}
}
I just wrote these beautiful functions. It also has the advantage of having no branching (a single if) for valid values. The hardest part is to craft the proper exception messages.
/// <summary>
/// Returns whether specified value is in valid range.
/// </summary>
/// <typeparam name="T">The type of data to validate.</typeparam>
/// <param name="value">The value to validate.</param>
/// <param name="min">The minimum valid value.</param>
/// <param name="minInclusive">Whether the minimum value is valid.</param>
/// <param name="max">The maximum valid value.</param>
/// <param name="maxInclusive">Whether the maximum value is valid.</param>
/// <returns>Whether the value is within range.</returns>
public static bool IsInRange<T>(this T value, T? min = null, bool minInclusive = true, T? max = null, bool maxInclusive = true)
where T : struct, IComparable<T>
{
var minValid = min == null || (minInclusive && value.CompareTo(min.Value) >= 0) || (!minInclusive && value.CompareTo(min.Value) > 0);
var maxValid = max == null || (maxInclusive && value.CompareTo(max.Value) <= 0) || (!maxInclusive && value.CompareTo(max.Value) < 0);
return minValid && maxValid;
}
/// <summary>
/// Validates whether specified value is in valid range, and throws an exception if out of range.
/// </summary>
/// <typeparam name="T">The type of data to validate.</typeparam>
/// <param name="value">The value to validate.</param>
/// <param name="name">The name of the parameter.</param>
/// <param name="min">The minimum valid value.</param>
/// <param name="minInclusive">Whether the minimum value is valid.</param>
/// <param name="max">The maximum valid value.</param>
/// <param name="maxInclusive">Whether the maximum value is valid.</param>
/// <returns>The value if valid.</returns>
public static T CheckRange<T>(this T value, string name, T? min = null, bool minInclusive = true, T? max = null, bool maxInclusive = true)
where T : struct, IComparable<T>
{
if (!value.IsInRange(min, minInclusive, max, maxInclusive))
{
if (min.HasValue && minInclusive && max.HasValue && maxInclusive)
{
var message = "{0} must be between {1} and {2}.";
throw new ArgumentOutOfRangeException(name, value, message.FormatInvariant(name, min, max));
}
else
{
var messageMin = min.HasValue ? GetOpText(true, minInclusive).FormatInvariant(min) : null;
var messageMax = max.HasValue ? GetOpText(false, maxInclusive).FormatInvariant(max) : null;
var message = (messageMin != null && messageMax != null) ?
"{0} must be {1} and {2}." :
"{0} must be {1}.";
throw new ArgumentOutOfRangeException(name, value, message.FormatInvariant(name, messageMin ?? messageMax, messageMax));
}
}
return value;
}
private static string GetOpText(bool greaterThan, bool inclusive)
{
return (greaterThan && inclusive) ? "greater than or equal to {0}" :
greaterThan ? "greater than {0}" :
inclusive ? "less than or equal to {0}" :
"less than {0}";
}
public static string FormatInvariant(this string format, params object?[] args) => string.Format(CultureInfo.InvariantCulture, format, args);
In C#, the optimal solution with regards to speed and codegen, with only one comparison, no bound checks and not error prone due to overflow is the following:
public static bool IsInRange(int value, int min, int max) => (uint)(value - min) <= (uint)(max - min);
Minimum and maximum value are inclusive.
This question already has answers here:
What is the algorithm to convert an Excel Column Letter into its Number?
(11 answers)
Closed 9 years ago.
I was wondering what is the best way to convert excel sheet column names into numbers.
I'm working with Excel Package, a good library to handle .xlsx documents. This library unfortunately doesn't have this functionality included.
OBS: The first column, A, corresponds
to number 1 in this library.
This function should work for an arbitrary length column name.
public static int GetColumnNumber(string name)
{
int number = 0;
int pow = 1;
for (int i = name.Length - 1; i >= 0; i--)
{
number += (name[i] - 'A' + 1) * pow;
pow *= 26;
}
return number;
}
I had to deal with this a few months ago. The inverse - column index to column name - is fun, too, and becomes really messy if you try to solve it with a zero based index not recognizing that this complicates things. It could be so simple if it would be a normal polyadic numeral system ...
Here is a simplified version of my solution as a extension method without error handling and all that stuff.
public static Int32 ToOneBasedIndex(this String name)
{
return name.ToUpper().
Aggregate(0, (column, letter) => 26 * column + letter - 'A' + 1);
}
I've been working with this for a while now and found this to work really good for columns that go beyond A-Z, or even beyond AA-ZZ... It's accomplished by breaking apart each character in the string and recursively calling itself to derive the DEC value of the ASCII character (less 64), then multiplying it by 26^n. A return value of long was used to overcome a potential limitation when n > 4.
public long columnNumber(String columnName)
{
char[] chars = columnName.ToUpper().ToCharArray();
return (long)(Math.Pow(26, chars.Count() - 1)) *
(System.Convert.ToInt32(chars[0]) - 64) +
((chars.Count() > 2) ? columnNumber(columnName.Substring(1, columnName.Length - 1)) :
((chars.Count() == 2) ? (System.Convert.ToInt32(chars[chars.Count() - 1]) - 64) : 0));
}
Also, if you'd like to get the inverse (i.e. pass in the columnNumber and get the columnName, here's some code that works for that.
public String columnName(long columnNumber)
{
StringBuilder retVal = new StringBuilder();
int x = 0;
for (int n = (int)(Math.Log(25*(columnNumber + 1))/Math.Log(26)) - 1; n >= 0; n--)
{
x = (int)((Math.Pow(26,(n + 1)) - 1) / 25 - 1);
if (columnNumber > x)
retVal.Append(System.Convert.ToChar((int)(((columnNumber - x - 1) / Math.Pow(26, n)) % 26 + 65)));
}
return retVal.ToString();
}
Source code:
namespace XLS
{
/// <summary>
/// Represents a single cell in a excell sheet
/// </summary>
public struct Cell
{
private long row;
private long column;
private string columnAddress;
private string address;
private bool dataChange;
/// <summary>
/// Initializes a new instance of the XLS.Cell
/// class with the specified row and column of excel worksheet
/// </summary>
/// <param name="row">The row index of a cell</param>
/// <param name="column">The column index of a cell</param>
public Cell(long row, long column)
{
this.row = row;
this.column = column;
dataChange = true;
address = string.Empty;
columnAddress = string.Empty;
}
/// <summary>
/// Initializes a new instance of the XLS.Cell
/// class with the specified address of excel worksheet
/// </summary>
/// <param name="address">The adress of a cell</param>
public Cell(string address)
{
this.address = address;
dataChange = false;
row = GetRow(address);
columnAddress = GetColumnAddress(address);
column = GetColumn(columnAddress);
}
/// <summary>
/// Gets or sets the row of this XLS.Cell
/// </summary>
public long Row
{
get { return row <= 0 ? 1 : row; }
set { row = value; dataChange = true; }
}
/// <summary>
/// Gets or sets the column of this XLS.Cell
/// </summary>
public long Column
{
get { return column <= 0 ? 1 : column; }
set { column = value; dataChange = true; }
}
/// <summary>
/// Gets or sets the address of this XLS.Cell
/// </summary>
public string Address
{
get { return dataChange ? ToAddress() : address; }
set
{
address = value;
row = GetRow(address);
column = GetColumn(address);
}
}
/// <summary>
/// Gets the column address of this XLS.Cell
/// </summary>
public string ColumnAddress
{
get { return GetColumnAddress(Address); }
private set { columnAddress = value; }
}
#region Private Methods
private static long GetRow(string address)
{
return long.Parse(address.Substring(GetStartIndex(address)));
}
private static string GetColumnAddress(string address)
{
return address.Substring(0, GetStartIndex(address)).ToUpperInvariant();
}
private static long GetColumn(string columnAddress)
{
char[] characters = columnAddress.ToCharArray();
int sum = 0;
for (int i = 0; i < characters.Length; i++)
{
sum *= 26;
sum += (characters[i] - 'A' + 1);
}
return (long)sum;
}
private static int GetStartIndex(string address)
{
return address.IndexOfAny("123456789".ToCharArray());
}
private string ToAddress()
{
string indexToString = string.Empty;
if (Column > 26)
{
indexToString = ((char)(65 + (int)((Column - 1) / 26) - 1)).ToString();
}
indexToString += (char)(65 + ((Column - 1) % 26));
dataChange = false;
return indexToString + Row;
}
#endregion
}
}
O24 has a column number and you want a name:
=LEFT(RIGHT(ADDRESS(1,O24),LEN(ADDRESS(1,O24))-1),FIND("$",RIGHT((ADDRESS(1,O24)),LEN(ADDRESS(1,O24))-1))-1)
O37 has a column name and you want a number:
=COLUMN(INDIRECT(O37&1))
public static string GetColumnName(int index)
{
const string letters = "ZABCDEFGHIJKLMNOPQRSTUVWXY";
int NextPos = (index / 26);
int LastPos = (index % 26);
if (LastPos == 0) NextPos--;
if (index > 26)
return GetColumnName(NextPos) + letters[LastPos];
else
return letters[LastPos] + "";
}