I have a variable representing a quantity in some given unit:
enum Unit
{
Single,
Thousand,
Million,
Billion,
Trillion
}
public class Quantity()
{
public double number;
public Unit numberUnit;
public Int64 GetNumberInSingleUnits()
{
// ???
}
}
For example, imagine
var GDP_Of_America = new Quantiy { number = 16.66, numberUnit = Unit.Trillion };
Int64 gdp = GDP_Of_America.GetNumberinSingleUnits(); // should return 16,660,000,000,000
My question is basically - how can I implement the "GetNumberInSingleUnits" function?
I can't just multiply with some UInt64 factor, e.g.
double num = 0.5;
UInt64 factor = 1000000000000;
var result = num * factor; // won't work! results in double
As the regular numeric operations reslt in a double, but the result may be larger than the range of valid doubles.
How could I do this conversion?
ps, I know the class "Quantity" is not a great way to store information - but this is bound by the input data of my application, which is in non-single (e.g. millions, billions etc) units.
Like I said, decimals can help you here:
public enum Unit
{
Micro = -6, Milli = -3, Centi = -2, Deci = -1,
One /* Don't really like this name */, Deca, Hecto, Kilo, Mega = 6, Giga = 9
}
public struct Quantity
{
public decimal Value { get; private set; }
public Unit Unit { get; private set; }
public Quantity(decimal value, Unit unit) :
this()
{
Value = value;
Unit = unit;
}
public decimal OneValue /* This one either */
{
get
{
return Value * (decimal)Math.Pow(10, (int)Unit);
}
}
}
With decimals you won't lose a lot of precision until after you decide to convert them to long (and beware of over/underflows).
Anton's answer seems like a good solution.
Just for the sake of discussion, another potential way.
I don't like this one at all as it seems very messy; However I think this might avoid imprecisions, if these ever turned out to be an issue with decimals.
public Int64 GetAsInt64(double number)
{
// Returns 1 for single units, 3 for thousands, 6 for millions, etc.
uint e = GetFactorExponent();
// Converts to scientific notation
// e.g. number = -1.2345, unit millions to "-1.2345e6"
string str = String.Format("{0:#,0.###########################}", number) + "e" + e;
// Parses scientific notation into Int64
Int64 result = Int64.Parse(str, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent | NumberStyles.AllowThousands);
return result;
}
Related
I have 2 arrays one of the types of numbers that will be used and the 2nd array is how many times that number can be used. I have a letter that determines what kind of method will be used I need to figure out how many times I can use a certain number from an array to determine a letter+number The ‘number’ is what I have to make with all the available numbers I can use. If the number cannot be made I would like to just say number cant be made or anything but allow the program to move on.
Here is what I have
int[] picksToUse = { 100, 50, 20, 10, 5, 1 };
int[] timesToUse = { 10, 10, 10, 10, 10, 10 };
string choice = Console.ReadLine();
string input = "";
if(choice.Length > 2)
{
input = choice.Substring(choice.IndexOf("$") + 1);
}
if(...){
}
else if (choice.Equals("D"))
{
int amt = Convert.ToInt32(input);
// code here to determine if number can be made with above choices
Dispense(amt, timesToUse);
}
Assuming picksToUse and timesToUse are exactly the same as you declared them, here's a way to know if you have enough of everything in stock to "pay up". It's a boolean function, which uses recursion. You would call it with the amount needed as parameter, and it would tell you right there if you have enough of everything.
Private Function HasCashInStock(amount As Integer, Optional index As Integer = 0) As Boolean
Dim billsNeeded As Integer = amount \ picksToUse(index)
If billsNeeded > timesToUse(index) Then
Return False
End If
amount -= picksToUse(index) * billsNeeded
If amount = 0 Then
Return True
End If
Return HasCashInStock(amount, index + 1)
End Function
The \ is an integer division operator (in VB.NET, at least - I'm shamelessly letting you translate this code). If you're not familiar with the integer division operator, well, when you use it with integer it gets rid of the floating numbers.
3 / 2 is not valid on integers, because it would yield 1.5.
3 \ 2 is valid on integers, and will yield 1.
That's all there is to it, really. Oh yeah, and recursion. I like recursion, but others will tell you to avoid it as much as you can. What can I say, I think that a nice recursive function has elegance.
You can also totally copy this function another time, modify it and use it to subtracts from your timesToUse() array once you know for sure that there's enough of everything to pay up.
If HasCashInStock(HereIsTheAmountAsInteger) Then
GivesTheMoney(HereIsTheAmountAsInteger)
End If
Having two functions is not the leanest code but it would be more readable. Have fun!
This is what I used to finish my project.
public static bool Validate(int amount, int[] total, int[] needed)
{
int[] billCount = total;
int[] cash = { 100, 50, 20, 10, 5, 1 };
int total = amount;
bool isValid = true;
for (int i = 0; i < total.Length; i++)
{
if(total >= cash[i])
{
billCount[i] = billCount[i] - needed[i];
}
if(billCount[i] < 0)
{
isValid = false;
break;
}
}
return isValid;
}
I got some working code. I did it with a class. I remember when I couldn't see what good classes were. Now I can't brush my teeth without a class. :-)
I force myself to do these problems to gain a little experience in C#. Now I have 3 things I like about C#.
class ATM
{
public int Denomination { get; set; }
public int Inventory { get; set; }
public ATM(int denom, int inven)
{
Denomination = denom;
Inventory = inven;
}
}
List<int> Bills = new List<int>();
List<ATM> ATMs = new List<ATM>();
private void OP2()
{
int[] picksToUse = { 100, 50, 20, 10, 5, 1 };
foreach (int d in picksToUse )
{
ATM atm = new ATM(d, 10);
ATMs.Add(atm);
}
//string sAmtRequested = Console.ReadLine();
string sAmtRequested = textBox1.Text;
if (int.TryParse(sAmtRequested, out int AmtRequested))
{
int RunningBalance = AmtRequested;
do
{
ATM BillReturn = GetBill(RunningBalance);
if (BillReturn is null)
{
MessageBox.Show("Cannot complete transaction");
return;
}
RunningBalance -= BillReturn.Denomination;
} while (RunningBalance > 0);
}
else
{
MessageBox.Show("Non-numeric request.");
return;
}
foreach (int bill in Bills)
Debug.Print(bill.ToString());
Debug.Print("Remaining Inventory");
foreach (ATM atm in ATMs)
Debug.Print($"For Denomination {atm.Denomination} there are {atm.Inventory} bills remaining");
}
private ATM GetBill(int RequestBalance)
{
var FilteredATMs = from atm in ATMs
where atm.Inventory > 0
orderby atm.Denomination descending
select atm;
foreach (ATM bill in FilteredATMs)
{
if (RequestBalance >= bill.Denomination )
{
bill.Inventory -= 1;
Bills.Add(bill.Denomination);
return bill;
}
}
return null;
}
This is the implementation from Microsoft for Sinh of a Complex
public static Complex Sinh(Complex value) /* Hyperbolic sin */
{
double a = value.m_real;
double b = value.m_imaginary;
return new Complex(Math.Sinh(a) * Math.Cos(b), Math.Cosh(a) * Math.Sin(b));
}
and the implementation for Cosh
public static Complex Cos(Complex value) {
double a = value.m_real;
double b = value.m_imaginary;
return new Complex(Math.Cos(a) * Math.Cosh(b), - (Math.Sin(a) * Math.Sinh(b)));
}
and finally the the implementation for Tanh
public static Complex Tanh(Complex value) /* Hyperbolic tan */
{
return (Sinh(value) / Cosh(value));
}
Source: https://referencesource.microsoft.com/System.Numerics/a.html#e62f37ac1d0c67da
I don't understand why Microsoft implented the Tanh method that way?
It will fail for very large values. E.g.:
tanh(709 + 0i) --> 1, ok
tanh(711 + 0i) --> NaN, failed should be 1
Any ideas how to improve the tanh method that?
For double the Math.Tanh methods works for large values.
The complex tanh method could be implemented like that:
public static Complex Tanh(Complex value)
{
double a = value.Real;
double b = value.Imaginary;
double tanh_a = Math.Tanh(a);
double tan_b = Math.Tan(b);
Complex num = new Complex(tanh_a, tan_b);
Complex den = new Complex(1, tanh_a * tan_b);
return num / den;
}
This will work as well for large values, see https://dotnetfiddle.net/xGWdQt.
Update
As well the complex tan method needs to be re-implemented that it works with larges values (imaginary part):
public static Complex Tan(Complex value)
{
double a = value.Real;
double b = value.Imaginary;
double tan_a = Math.Tan(a);
double tanh_b = Math.Tanh(b);
Complex num = new Complex(tan_a, tanh_b);
Complex den = new Complex(1, -tan_a * tanh_b);
return num / den;
}
See https://dotnetfiddle.net/dh6CSG.
Using the comment from Hans Passant another way to implement the tanh method would be:
public static Complex Tanh(Complex value)
{
if (Math.Abs(value.Real) > 20)
return new Complex(Math.Sign(value.Real), 0);
else
return Complex.Tanh(value);
}
See https://dotnetfiddle.net/QvUECX.
And the tan method:
public static Complex Tan(Complex value)
{
if (Math.Abs(value.Imaginary) > 20)
return new Complex(0, Math.Sign(value.Imaginary));
else
return Complex.Tan(value);
}
See https://dotnetfiddle.net/Xzclcu.
I have following list:
100 -> 1.0 99 -> 1.1 98 -> 1.1 97 -> 1.2 ...
23-28 -> 5.6 ... 0-5 -> 6.0
On the left side are the maximal reached points, on the right side the grade.
This list contains around 40 different Points -> Grade. So my program is calculating the points of the exam, and in the end it should say 100 Points reached, u got the grade 1.0 ... 3 Points reached -> 6.0 ...
On my current knowledge, I know only switch case, but I think it's not the best way to realize it.
I'd start off with a data structure for the list you have. (This is assuming C# 6, by the way - for earlier versions of C# you wouldn't be able to use an auto-implemented readonly property, but that's about the only difference.)
public sealed class GradeBand
{
public int MinScore { get; }
public int MaxScore { get; } // Note: inclusive!
public decimal Grade { get; }
public GradeBand(int minScore, int maxScore, decimal grade)
{
// TODO: Validation
MinScore = minScore;
MaxScore = maxScore;
Grade = grade;
}
}
You can construct your list with:
var gradeBands = new List<GradeBand>
{
new GradeBand(0, 5, 6.0m),
...
new GradeBand(23, 28, 5.6m),
...
new GradeBand(100, 100, 1.0m),
};
You'd probably want some sort of validation that the bands covered the whole range of grades.
Then there are two fairly obvious options for finding the grade. Firstly, a linear scan with no preprocessing:
public decimal FindGrade(IEnumerable<GradeBand> bands, int score)
{
foreach (var band in bands)
{
if (band.MinScore <= score && score <= band.MaxScore)
{
return band.Grade;
}
}
throw new ArgumentException("Score wasn't in any band");
}
Or you could preprocess the bands once:
var scoreToGrade = new decimal[101]; // Or whatever the max score is
foreach (var band in bands)
{
for (int i = band.MinScore; i <= band.MaxScore; i++)
{
scoreToGrade[i] = band.Grade;
}
}
Then for each score you can just use:
decimal grade = scoreToGrade[score];
Try this sample
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Dictionary<int, double> dictionary =
new Dictionary<int, double>();
dictionary.Add(100, 1.0);
dictionary.Add(99, 1.1);
//Add more item here
// See whether Dictionary contains a value.
if (dictionary.ContainsKey(100))
{
double value = dictionary[100];
Console.WriteLine(String.Format("{0:0.0}",value));
}
Console.ReadLine();
}
}
Is it possible to convert float to double, then back without losing precision? I mean first float should be exaclty bit by bit same like result float.
Yes, and we can test it:
float fl = float.NegativeInfinity;
long cycles = 0;
while (true)
{
double dbl = fl;
float fl2 = (float)dbl;
int flToInt1 = new Ieee754.Int32SingleConverter { Single = fl }.Int32;
int flToInt2 = new Ieee754.Int32SingleConverter { Single = fl2 }.Int32;
if (flToInt1 != flToInt2)
{
Console.WriteLine("\nDifferent: {0} (Int32: {1}, {2})", fl, flToInt1, flToInt2);
}
if (fl == 0)
{
Console.WriteLine("\n0, Sign: {0}", flToInt1 < 0 ? "-" : "+");
}
if (fl == float.PositiveInfinity)
{
fl = float.NaN;
}
else if (float.IsNaN(fl))
{
break;
}
else
{
fl = Ieee754.NextSingle(fl);
}
cycles++;
if (cycles % 100000000 == 0)
{
Console.Write(".");
}
}
Console.WriteLine("\nDone");
Console.ReadKey();
and the utility classes:
public static class Ieee754
{
[StructLayout(LayoutKind.Explicit)]
public struct Int32SingleConverter
{
[FieldOffset(0)]
public int Int32;
[FieldOffset(0)]
public float Single;
}
public static float NextSingle(float value)
{
int bits = new Int32SingleConverter { Single = value }.Int32;
if (bits >= 0)
{
bits++;
}
else if (bits != int.MinValue)
{
bits--;
}
else
{
bits = 0;
}
return new Int32SingleConverter { Int32 = bits }.Single;
}
}
On my computer, in Release Mode, without the debugger (Ctrl+F5 from Visual Studio), it is around 2 minutes.
There are around 4 billion different float values. I cast them around and convert them to int to binary check them. Note that NaN values are "particular". The IEEE754 standard has multiple values for NaN, but .NET "compresses" them to a single NaN value. So you could create a NaN value (manually, through bit manipulation) that wouldn't be converted back and forth correctly. The "standard" NaN values is converted correctly, so are PositiveInfinity and NegativeInfinity, +0 and -0.
Yes, as every float can be exactly represented as a double, the round trip will give you the exact value that you started with.
There is one possible technical exception to your requirement that they are bit-by-bit the same: there are multiple bit patterns that correspond to NaN values (this is often referred to as the "NaN payload"). As far as I know, there is no strict requirement that this be preserved: you will still get a NaN, just maybe a slightly different one.
In C#, can you use number ranges in enum types, for example
public enum BookType
{
Novel = 1,
Journal = 2,
Reference = 3,
TextBook = 4 .. 10
}
EDIT: The reason this is needed is to cast from a number to the enum type, eg:
int iBook = 5
BookType btBook = (BookType)ibook
Debug.Print "Book " + ibook + " is a " btBook
and the expected output is: Book 5 is a TextBook
As others have said, no it isn't possible. It is possible to combine enum values if they are flags:
[Flags]
public enum BookType
{
Novel = 0,
Journal = 1 << 0,
Reference = 1 << 1,
TextBook1 = 1 << 2,
TextBook2 = 1 << 3,
TextBook3 = 1 << 4,
TextBook4 = 1 << 5,
TextBook5 = 1 << 6,
TextBooks1To5 = TextBook1 | TextBook2 | TextBook3 | TextBook4 | TextBook5
}
According to the C# standard (p612, The C# Programming Language) the value given to an enumeration must be a constant integer (or any similar type - long, byte, sbyte, short, etc), so a range of values isn't valid.
My compiler (VS2008) agrees with the spec.
Since you can't repeat names within an enumeration, the closest you'll get is something like this:
public enum BookType
{
Novel = 1,
Journal = 2,
Reference = 3,
TextBook4 = 4,
TextBook5 = 5, ...
TextBook10 = 10
}
Which is actually pretty ugly. Perhaps an enum is not the solution to your particular problem ...
Since you are unable to assign a value range to an enum, I thought of an alternative approach in order to assign an enum as a limit value (the example is based on time):
private enum eTiming
{
eOnTime = 0,
eSlightDelay = 5,
eMinorDelay = 15,
eDelayed = 30,
eMajorDelay = 45,
eSevereDelay = 60
}
private static eTiming CheckIfTimeDelayed(TimeSpan tsTime)
{
eTiming etiming = eTiming.eOnTime;
foreach (eTiming eT in Enum.GetValues(typeof(eTiming)))
{
if (Convert.ToInt16(eT) <= tsTime.TotalMinutes)
etiming = eT;
}
return etiming;
}
This is assuming that the enum is sorted, and works unexpectedly with signed (-) values.
Somewhat offtopic, you can simulate enums using normal classes with readonly fields.
e.g. something similair to this would solve your problem:
public sealed class BookType
{
public static readonly BookType Novel = new BookType(1, 1, "Novel");
public static readonly BookType Journal = new BookType(2, 2, "Journal");
public static readonly BookType Reference = new BookType(3, 3, "Reference");
public static readonly BookType Textbook = new BookType(4, 10, "Textbook");
public int Low { get; private set; }
public int High { get; private set; }
private string name;
private static class BookTypeLookup
{
public static readonly Dictionary<int, BookType> lookup = new Dictionary<int, BookType>();
}
private BookType(int low, int high, string name)
{
this.Low = low;
this.High = high;
this.name = name;
for (int i = low; i <= high; i++)
BookTypeLookup.lookup.Add(i, this);
}
public override string ToString()
{
return name;
}
public static implicit operator BookType(int value)
{
BookType result = null;
if (BookTypeLookup.lookup.TryGetValue(value, out result))
return result;
throw new ArgumentOutOfRangeException("BookType not found");
}
}
It's quite a bit more verbose than a normal enum, but it does allow you to define ranged members in an enum like manner.
e.g.
var bookType = (BookType)5;
Console.WriteLine(bookType);
If you can assign the values to enum-strings yourself then you can use some bitmagic to map multiple int values to same enum value. Subtypes could be enums themselves for every BookType (NovelTypes, JournalTypes, etc).
On the downside
it does require some value modification when casting to BookType
every subtype range is of the same size (16 in current example.
it is a bit less readable than simple Novel = 3 kind of mapping.
Example code:
class Program
{
/// <summary> Number of subtypes reserved for each BookType. </summary>
private const byte BookTypeStep = 16;
/// <summary> Bitmask to use to extract BookType from a byte. </summary>
private const byte BookTypeExtractor = Byte.MaxValue - BookTypeStep + 1;
/// <summary> Bitmask to use to extract Book subtype from a byte. </summary>
private const byte BookSubTypeExtractor = BookTypeStep -1;
public enum BookType : byte
{
Unknown = 0,
Novel = BookTypeStep * 1,
Journal = BookTypeStep * 2,
Reference = BookTypeStep * 3,
TextBook = BookTypeStep * 4,
}
static void Main(string[] args)
{
for(int i = 16; i < 80; i++)
{
Console.WriteLine("{0}\tof type {1} ({2}),\tsubtype nr {3}",
i,
i & BookTypeExtractor,
(BookType)(i & BookTypeExtractor),
i & BookSubTypeExtractor
);
}
Console.ReadLine();
}
}
This example has ranges 16-31 for Novels, 32-47 for journals, etc.
No, it's not. If the numeric constants you're trying to map to truly have the same meaning, you would still need a separate member for each numeric constant. Like TextBook4, TextBook5, etc.
You can opt for a dictionary rather.
var BookType = new Dictionary<int, string>();
BookType.Add(1, "Novel");
BookType.Add(2, "Journal");
BookType.Add(3, "Reference");
BookType.Add(4, "TextBook");
BookType.Add(5, "TextBook");
BookType.Add(6, "TextBook");
BookType.Add(7, "TextBook");
BookType.Add(8, "TextBook");
BookType.Add(9, "TextBook");
BookType.Add(10, "TextBook");
int iBook = 5
Debug.Print "Book " + iBook + " is a " BookType[iBook]
Edit: You can also declare your dictionary readonly if it's in class level.
You can use an enum as the Dictionary value instead of string.
Perhaps you meant to ask a related question, which is: can you have more than one enumeration (not sure I have the terminology correct, but my example will show what I mean) for each value?
In C#, you can do something like this:
public enum BookType
{
Novel = 1,
Journal = 2,
Magazine = 2,
Reference = 3,
TextBook = 4,
LabWorkbook = 4,
Dictionary = 5,
Encyclopedia = 5
}
This way, you can use either BookType.Journal or BookType.Magazine in your code, either of which is synonymous with the value 2. Whether this should be done is another matter - I'm not familiar with the arguments for or against this (I'd like to say "if C# allows it, it must be OK", but that would be utterly crazy).
The simplest answer to your question is No. The easiest way to accomplish what you desire is:
public enum BookType
{
Novel = 1,
Journal = 2,
Reference = 3,
TextBook = 4
}
public void bookOutput(int book)
{
if(book < 4)
Console.Writeline("Book "+book+" is a " + ((BookType)book).ToString());
else
Console.Writeline("Book "+book+" is a " + BookType.TextBook.ToString());
}
The idea is to let enum be individual values and handle the range with logic statements.