I am using following code to implement Luhn algorithm for credit card check in C# language, but could not get the output to generate the check sum its showing validity. Kindly help me. Thank you in advance.
public class Program
{
private static void Main(string[]creditcard)
{
int sum = 0, d;
string num ="7992739871";
int a = 0;
for (int i = num.Length - 2; i >= 0; i--)
{
d = Convert.ToInt32(num.Substring(i, 1));
if (a % 2 == 0)
d = d * 2;
if (d > 9)
d -= 9;
sum += d;
a++;
}
if ((10 - (sum % 10) == Convert.ToInt32(num.Substring(num.Length - 1))))
Console.WriteLine("valid");
Console.WriteLine("sum of digits of the number" + sum);
}
}
Here are some extension methods that compute a Luhn checkdigit, validate a number with a checkdigit, and add a checkdigit to a number. Tested in .NET 4.5.
There are extension methods for strings, ints, int64s and IList.
I got some ideas for this from rosettacode.org
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
public static class CheckDigitExtension
{
static readonly int[] Results = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 };
#region extension methods for IList<int>
/// <summary>
/// For a list of digits, compute the ending checkdigit
/// </summary>
/// <param name="digits">The list of digits for which to compute the check digit</param>
/// <returns>the check digit</returns>
public static int CheckDigit(this IList<int> digits)
{
var i = 0;
var lengthMod = digits.Count%2;
return (digits.Sum(d => i++ % 2 == lengthMod ? d : Results[d]) * 9) % 10;
}
/// <summary>
/// Return a list of digits including the checkdigit
/// </summary>
/// <param name="digits">The original list of digits</param>
/// <returns>the new list of digits including checkdigit</returns>
public static IList<int> AppendCheckDigit(this IList<int> digits)
{
var result = digits;
result.Add(digits.CheckDigit());
return result;
}
/// <summary>
/// Returns true when a list of digits has a valid checkdigit
/// </summary>
/// <param name="digits">The list of digits to check</param>
/// <returns>true/false depending on valid checkdigit</returns>
public static bool HasValidCheckDigit(this IList<int> digits)
{
return digits.Last() == CheckDigit(digits.Take(digits.Count - 1).ToList());
}
#endregion extension methods for IList<int>
#region extension methods for strings
/// <summary>
/// Internal conversion function to convert string into a list of ints
/// </summary>
/// <param name="digits">the original string</param>
/// <returns>the list of ints</returns>
private static IList<int> ToDigitList(this string digits)
{
return digits.Select(d => d - 48).ToList();
}
/// <summary>
/// For a string of digits, compute the ending checkdigit
/// </summary>
/// <param name="digits">The string of digits for which to compute the check digit</param>
/// <returns>the check digit</returns>
public static string CheckDigit(this string digits)
{
return digits.ToDigitList().CheckDigit().ToString(CultureInfo.InvariantCulture);
}
/// <summary>
/// Return a string of digits including the checkdigit
/// </summary>
/// <param name="digits">The original string of digits</param>
/// <returns>the new string of digits including checkdigit</returns>
public static string AppendCheckDigit(this string digits)
{
return digits + digits.CheckDigit();
}
/// <summary>
/// Returns true when a string of digits has a valid checkdigit
/// </summary>
/// <param name="digits">The string of digits to check</param>
/// <returns>true/false depending on valid checkdigit</returns>
public static bool HasValidCheckDigit(this string digits)
{
return digits.ToDigitList().HasValidCheckDigit();
}
#endregion extension methods for strings
#region extension methods for integers
/// <summary>
/// Internal conversion function to convert int into a list of ints, one for each digit
/// </summary>
/// <param name="digits">the original int</param>
/// <returns>the list of ints</returns>
private static IList<int> ToDigitList(this int digits)
{
return digits.ToString(CultureInfo.InvariantCulture).Select(d => d - 48).ToList();
}
/// <summary>
/// For an integer, compute the ending checkdigit
/// </summary>
/// <param name="digits">The integer for which to compute the check digit</param>
/// <returns>the check digit</returns>
public static int CheckDigit(this int digits)
{
return digits.ToDigitList().CheckDigit();
}
/// <summary>
/// Return an integer including the checkdigit
/// </summary>
/// <param name="digits">The original integer</param>
/// <returns>the new integer including checkdigit</returns>
public static int AppendCheckDigit(this int digits)
{
return digits * 10 + digits.CheckDigit();
}
/// <summary>
/// Returns true when an integer has a valid checkdigit
/// </summary>
/// <param name="digits">The integer to check</param>
/// <returns>true/false depending on valid checkdigit</returns>
public static bool HasValidCheckDigit(this int digits)
{
return digits.ToDigitList().HasValidCheckDigit();
}
#endregion extension methods for integers
#region extension methods for int64s
/// <summary>
/// Internal conversion function to convert int into a list of ints, one for each digit
/// </summary>
/// <param name="digits">the original int</param>
/// <returns>the list of ints</returns>
private static IList<int> ToDigitList(this Int64 digits)
{
return digits.ToString(CultureInfo.InvariantCulture).Select(d => d - 48).ToList();
}
/// <summary>
/// For an integer, compute the ending checkdigit
/// </summary>
/// <param name="digits">The integer for which to compute the check digit</param>
/// <returns>the check digit</returns>
public static int CheckDigit(this Int64 digits)
{
return digits.ToDigitList().CheckDigit();
}
/// <summary>
/// Return an integer including the checkdigit
/// </summary>
/// <param name="digits">The original integer</param>
/// <returns>the new integer including checkdigit</returns>
public static Int64 AppendCheckDigit(this Int64 digits)
{
return digits * 10 + digits.CheckDigit();
}
/// <summary>
/// Returns true when an integer has a valid checkdigit
/// </summary>
/// <param name="digits">The integer to check</param>
/// <returns>true/false depending on valid checkdigit</returns>
public static bool HasValidCheckDigit(this Int64 digits)
{
return digits.ToDigitList().HasValidCheckDigit();
}
#endregion extension methods for int64s
}
Here are some XUnit test cases that show how the extension methods work.
public class CheckDigitExtensionShould
{
[Fact]
public void ComputeCheckDigits()
{
Assert.Equal(0, (new List<int> { 0 }).CheckDigit());
Assert.Equal(8, (new List<int> { 1 }).CheckDigit());
Assert.Equal(6, (new List<int> { 2 }).CheckDigit());
Assert.Equal(0, (new List<int> { 3, 6, 1, 5, 5 }).CheckDigit());
Assert.Equal(0, 36155.CheckDigit());
Assert.Equal(8, (new List<int> { 3, 6, 1, 5, 6 }).CheckDigit());
Assert.Equal(8, 36156.CheckDigit());
Assert.Equal(6, 36157.CheckDigit());
Assert.Equal("6", "36157".CheckDigit());
Assert.Equal("3", "7992739871".CheckDigit());
}
[Fact]
public void ValidateCheckDigits()
{
Assert.True((new List<int> { 3, 6, 1, 5, 6, 8 }).HasValidCheckDigit());
Assert.True(361568.HasValidCheckDigit());
Assert.True("361568".HasValidCheckDigit());
Assert.True("79927398713".HasValidCheckDigit());
}
[Fact]
public void AppendCheckDigits()
{
Console.WriteLine("36156".CheckDigit());
Console.WriteLine("36156".AppendCheckDigit());
Assert.Equal("361568", "36156".AppendCheckDigit());
Assert.Equal("79927398713", "7992739871".AppendCheckDigit());
}
}
Compact Luhn check:
public static bool Luhn(string digits)
{
return digits.All(char.IsDigit) && digits.Reverse()
.Select(c => c - 48)
.Select((thisNum, i) => i % 2 == 0
? thisNum
:((thisNum *= 2) > 9 ? thisNum - 9 : thisNum)
).Sum() % 10 == 0;
}
Fiddle: https://dotnetfiddle.net/CCwE48
Here is a correct and fast implementation:
bool PassesLuhnCheck(string value)
{
long sum = 0;
for (int i = 0; i < value.Length; i++)
{
var digit = value[value.Length - 1 - i] - '0';
sum += (i % 2 != 0) ? GetDouble(digit) : digit;
}
return sum % 10 == 0;
int GetDouble(long i)
{
switch (i)
{
case 0: return 0;
case 1: return 2;
case 2: return 4;
case 3: return 6;
case 4: return 8;
case 5: return 1;
case 6: return 3;
case 7: return 5;
case 8: return 7;
case 9: return 9;
default: return 0;
}
}
}
I have tried this code which might help for other future folk:
public string GenerateLuhnNumber(string baseNumber)
{
if (!double.TryParse(baseNumber, out double baseNumberInt))
throw new InvalidWorkflowException($"Field contains non-numeric character(s) : {baseNumber}");
var step2 = string.Empty;
for (var index = baseNumber.Length - 1; index >= 0; index -= 2)
{
var doubleTheValue = (int.Parse(baseNumber[index].ToString())) * 2;
if (doubleTheValue > 9)
doubleTheValue = Math.Abs(doubleTheValue).ToString().Sum(c => Convert.ToInt32(c.ToString()));
step2 = step2.Insert(0, (index != 0 ? baseNumber[index - 1].ToString() : "") + doubleTheValue);
}
var step3 = Math.Abs(Convert.ToDouble(step2)).ToString(CultureInfo.InvariantCulture).Sum(c => Convert.ToDouble(c.ToString())).ToString(CultureInfo.InvariantCulture);
var lastDigitStep3 = Convert.ToInt32(step3[step3.Length - 1].ToString());
string checkDigit = "0";
if (lastDigitStep3 != 0)
checkDigit = (10 - lastDigitStep3).ToString();
return baseNumber + checkDigit;
}
You can do it very simply (reference),
public static bool Mod10Check(string creditCardNumber)
{
// check whether input string is null or empty
if (string.IsNullOrEmpty(creditCardNumber))
{
return false;
}
int sumOfDigits = creditCardNumber.Where((e) => e >= '0' && e <= '9')
.Reverse()
.Select((e, i) => ((int)e - 48) * (i % 2 == 0 ? 1 : 2))
.Sum((e) => e / 10 + e % 10);
return sumOfDigits % 10 == 0;
}
This one will do it I believe:
static void Main(string[] args)
{
string number = "1762483";
int digit = 0;
int sum = 0;
for (int i = 0; i <= number.Length - 1; i++)
{
if (i % 2 == 1)
{
digit = int.Parse(number.Substring(i, 1));
sum += DoubleDigitValue(digit);
Console.WriteLine(digit);
}
else
{
digit = int.Parse(number.Substring(i, 1));
sum += digit;
}
}
Console.WriteLine(sum);
if (sum % 10 == 0)
{
Console.WriteLine("valid");
}
else
{
Console.WriteLine("Invalid");
}
}
static int DoubleDigitValue(int digit)
{
int sum;
int doubledDigit = digit * 2;
if (doubledDigit >= 10)
{
sum = 1 + doubledDigit % 10;
} else
{
sum = doubledDigit;
}
return sum;
}
These are my methods for validating and calculating the last digit. To validate a number simply check that the result of the first method is 0;
private int LuhnChecksum(string input)
{
var length = input.Length;
var even = length % 2;
var sum = 0;
for (var i = length - 1; i >= 0; i--)
{
var d = int.Parse(input[i].ToString());
if (i % 2 == even)
d *= 2;
if (d > 9)
d -= 9;
sum += d;
}
return sum % 10;
}
private int LuhnCalculateLastDigit(string input)
{
var checksum = LuhnChecksum(input + "0");
return checksum == 0 ? 0 : 10 - checksum;
}
I just interprete code from C to C#. Code in C you can find there:(https://uk.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9B%D1%83%D0%BD%D0%B0). I cheked it for a few device.
byte[] data = new byte[19];
//fill the data[]
...
//use it
if (checkByLuhn(data))
{
//check complete
}
...
private bool checkByLuhn(byte[] pPurposed)
{
int nSum = 0;
int nDigits = pPurposed.Length;
int nParity = (nDigits - 1) % 2;
char[] cDigit = new char[] { '0','\0' };
for (int i = nDigits; i > 0; i--)
{
cDigit[0] = (char)pPurposed[i - 1];
int nDigit = (int)Char.GetNumericValue(cDigit[0]);
if (nParity == i % 2)
{
nDigit = nDigit * 2;
}
nSum += nDigit / 10;
nSum += nDigit % 10;
}
return 0 == nSum % 10;
}
Philippe had an excellent answer, but here's a simpler version that is still O(n). I've tested it in xUnit with a dataset of 30 and it is factors faster than some of the upvoted answers.
public static bool CheckLuhnParity(string digits)
{
bool isValid = false;
if (!string.IsNullOrEmpty(digits))
{
long sum = 0;
int parity = digits.Length % 2;
for (int i = 0; i < digits.Length; i++)
{
int digit = digits[^(i + 1)] - '0';
sum += (i % 2 == parity) ? Luhn(digit) : digit;
}
isValid = (sum % 10) == 0;
}
return isValid;
int Luhn(int digit) => (digit *= 2) > 9 ? digit - 9 : digit;
}
This has the same flaw as the accepted answer, though; it doesn't fully implement the Luhn algorithm. It assumes that the actual check digit does not need to be verified which means invalid numbers may be accepted. Here's a better way:
public static bool CheckLuhnDigit(string digits)
{
bool isValid = false;
if (!string.IsNullOrEmpty(digits) && digits.Length > 2)
{
long sum = 0;
for (int i = 0; i < digits.Length - 1; i++)
{
int digit = digits[^(i + 2)] - '0';
sum += (i % 2 == 0) ? Luhn(digit) : digit;
}
int checkDigit = digits[^1] - '0';
isValid = (10 - (sum % 10)) % 10 == checkDigit;
}
return isValid;
int Luhn(int digit) => (digit *= 2) > 9 ? digit - 9 : digit;
}
Does anyone want to attempt O(log n)?
Here's shorter version to get checksum
private int getCheckSum(string number)
{
var sum = number.Reverse() //Reverse
.Select((d, i) => i % 2 == 0 ? Convert.ToInt32(d.ToString()) * 2 : Convert.ToInt32(d.ToString())) //double every 2nd digit including starting
.Select(x => x.ToString().Select(c => Convert.ToInt32(c.ToString())).Sum()) //sum double digit number 18 = 1 + 8 = 9
.Sum(); //Sum all
return (10 - (sum % 10)) % 10;
}
To validate a check sum, pass number without checksum and compare the result with last digit of original number .
Your algorithm is correct, but you're testing it wrong way.
I can see your sample input is from wiki page: Luhn algorithm. Difference is, they are calculating check digit for "7992739871X", where X is the check digit they're looking for. Your code validates number your already have!
Change your input to "79927398713" and it will mark it as correct number.
Update
OK, I see where is the problem. You're not taking this part of algorithm right:
From the rightmost digit, which is the check digit, moving left, double the value of every second digit;
Your code takes every other digit, but not necessary starting from most left digit. Try this code:
for (int i = 0; i < num.Length; i++)
{
d = Convert.ToInt32(num.Substring(num.Length - 1 - i, 1));
if (a % 2 == 0)
d = d * 2;
if (d > 9)
d -= 9;
sum += d;
a++;
}
var checkDigit = 10 - (sum % 10);
Related
I have the code which prints all possible permutations of a given string. How to set the length of one permutation? For example if the lenght is 2 then output should contains 6 possible permutations from ABCD.
class GFG
{
/**
* permutation function
* #param str string to
calculate permutation for
* #param l starting index
* #param r end index
*/
private static void permute(String str,
int l, int r)
{
if (l == r)
Console.WriteLine(str);
else
{
for (int i = l; i <= r; i++)
{
str = swap(str, l, i);
permute(str, l + 1, r);
str = swap(str, l, i);
}
}
}
/**
* Swap Characters at position
* #param a string value
* #param i position 1
* #param j position 2
* #return swapped string
*/
public static String swap(String a,
int i, int j)
{
char temp;
char[] charArray = a.ToCharArray();
temp = charArray[i] ;
charArray[i] = charArray[j];
charArray[j] = temp;
string s = new string(charArray);
return s;
}
// Driver Code
public static void Main()
{
String str = "ABCD";
int n = str.Length;
permute(str, 0, n-1);
}
}
I originally missed that this was using a variable number of number arrangements (i.e. 5 source characters to all of the 2 character strings that could be generated). I've since revised this to show extra detail.
This is probably a mathematic rather than programming questions.
In order to calculate the number of permutations for source characters c with the maximum output length l, use the following:
result = c! / (c - l)!
In the case of your example of 4 characters and a maximum of 2-character output, this gives:
result = 4! / (4 - 2)!
= 4! / 2!
= 24 / 2
= 12
To calculate this in C# is not difficult - calculate the factorial (!) of c and the difference between c and l and divide the first by the second:
Using the handy function below:
/// <summary>
/// Gets the factorial of the specified number.
/// </summary>
/// <param name="n">An int indicating the number to get the factorial of.</param>
/// <returns>An int indicating the factorial.</returns>
private static int getFactorial(int n)
{
int returnValue = 1;
while (n > 1)
returnValue *= n--;
return returnValue;
}
This can be done using:
int result = getFactorial(4) / getFactorial(4 - 2);
Console.WriteLine(result);
Output:
12
This can also be placed into its own function:
/// <summary>
/// Gets the factorial of n to length l.
/// </summary>
/// <param name="n">An int indicating the number of items in the set.</param>
/// <param name="l">An int indicating the length of the output.</param>
/// <returns>An int indicating the result.</returns>
private static int getFactorial(int n, int l)
{
if (l > n) throw new ArgumentException("The legnth of the output may not be larger than the number of items", nameof(l));
return getFactorial(n) / getFactorial(n - l);
}
Used as such:
Console.WriteLine($"The factorial of 4 by 2 is {getFactorial(4, 2)}");
Console.WriteLine($"The factorial of 5 by 3 is {getFactorial(5, 3)}");
Console.WriteLine($"The factorial of 6 by 2 is {getFactorial(6, 2)}");
Outputs:
The factorial of 4 by 2 is 12
The factorial of 5 by 3 is 60
The factorial of 6 by 2 is 30
Note: Using an int may not be the best choice. At low numbers it works well but as soon as you have a 13-character string (13!) it will overflow and give an invalid result. 13! = 6,227,020,800 which is clearly bigger than an int32 in C#.
Given this problem:
Consider two of the planets in the orbital system: Earth and Mars.
Assume the Earth orbits the Sun in exactly 365 Earth days, and Mars
orbits the Sun in exactly 687 Earth days. Thus the Earth’s orbit
starts at day 0 and continues to day 364, and then starts over at day
0. Mars orbits similarly, but on a 687-day time scale.
We would like to find out how long it will take until both planets are
on day. 0 of their orbits simultaneously. Write a program that can
determine this.
Input Format:
The first line of input contains an integer N indicating the number of
test cases. N lines follow. Each test case contains two integers E and
M. These indicate which days Earth and Mars are at their respective
orbits.
Output Format:
For each case, display the case number followed by the smallest number
of days until the two planets will both be on day 0 of their orbits.
Follow the format of the sample output.
Sample Input 1
0 0
364 686
360 682
0 1
1 0
Sample Output 1
Case 1: 0
Case 2: 1
Case 3: 5
Case 4: 239075
Case 5: 11679
I tried solving the problem using modules but it doesn't seem correct
static string readInput;
static string firstStr = "";
static string secondStr = "";
static int firstInput;
static int secondInput;
static int testCases = 10;
static int caseNumber = 1;
static int outPut;
caseNumber <= testCases
static void Main(string[] args) {
//recall runProcess as long caseNumber is less or equal testCases
while (caseNumber <= testCases) {
runProcess();
Console.WriteLine("Case " + caseNumber + ": " + outPut);
caseNumber++;
}
}
Read input from console:
/// <summary>
/// This is the main process, is extracted to void so we can recall it.
/// </summary>
public static void runProcess() {
readInput = Console.ReadLine();
if (readInput != null) {
for (int i = 0; i < readInput.Length; i++) {
secondStr = secondStr + readInput[i];
if (readInput[i] == ' ') {
firstStr = secondStr;
secondStr = "";
continue;
}
}
}
firstInput = Convert.ToInt32(firstStr);
secondInput = Convert.ToInt32(secondStr);
outPut = atZero(firstInput, secondInput);
}
/// <summary>
/// This method takes the input data from the console to later determine the zero point
/// </summary>
/// <param name="earthDays"></param>
/// <param name="marsDays"></param>
/// <returns></returns>
public static int atZero(int earthDays, int marsDays) {
int earthOrbit = 365;
int marsOrbit = 687;
int modEarth = earthOrbit;
int modMars = marsOrbit;
int earthDistinction = earthOrbit - earthDays;
int marsDistinction = marsOrbit - marsDays;
if ((modInverse(earthDistinction, marsDistinction, modMars)) == 0) {
return (modInverse(marsDistinction, earthDistinction, modEarth)) * marsDistinction;
} else {
return (modInverse(earthDistinction, marsDistinction, modMars)) * earthDistinction;
}
}
mod invert
/// <summary>
/// The method below takes a denominator, numerator and a mod to later invert the mod.
/// </summary>
/// <param name="denominator"></param>
/// <param name="numerator"></param>
/// <param name="mod"></param>
/// <returns>modInverse</returns>
static int modInverse(int denominator, int numerator, int mod) {
int i = mod, outputAll = 0, d = numerator;
while (denominator > 0) {
int divided = i / denominator, x = denominator;
denominator = i % x;
i = x;
x = d;
d = outputAll - divided * x;
outputAll = x;
}
outputAll %= mod;
if (outputAll < 0) outputAll = (outputAll + mod) % mod;
return outputAll;
}
Is there any way to solve the problem without modules?
Thanks.
A straight forward way to calculate a solution could be this method:
private static int DaysTillBothAt0(int currentEarthDay, int currentMarsDay)
{
int result = 0, earth = currentEarthDay, mars = currentMarsDay;
while (earth != 0 || mars != 0)
{
result += 1;
earth = (earth + 1) % 365;
mars = (mars + 1) % 687;
}
return result;
}
This is of course not the fastest alogrithm or mathematically extraordinary elegant, but for the required data range performance doesn't matter here at all. (I don't know what your teacher expects, though).
It simply counts the orbits forward until they meet at 0.
You can use this for your test cases like this:
result = DaysTillBothAt0(0, 0); // 0
result = DaysTillBothAt0(364, 686); // 1
result = DaysTillBothAt0(360, 682); // 5
result = DaysTillBothAt0(0, 1); // 239075
result = DaysTillBothAt0(1, 0); // 11679
One more solution for this problem
private static int DaysTillBothAt0(int currentEarthday, int currentMarsday) {
int count = 365 - currentEarthday;
currentMarsday = (currentMarsday + count) % 687;
while (currentMarsday != 0) {
currentMarsday = (currentMarsday + 365) % 687;
count += 365;
}
return currentMarsday;
}
I'm developing a project using DirectShow .NET.
I'm trying to integrate a library called "WPF Sound Visualization Library" which creates a spectrum analyzer visual.
In order for the visual to work I need to implement these 2 methods in my player:
GetFFTData(float[] fftDataBuffer) - Assigns current FFT data to a buffer.
Remarks: The FFT data in the buffer should consist only of the real number intensity values. This means that if your FFT algorithm returns complex numbers (as many do), you'd run an algorithm similar to: for(int i = 0; i < complexNumbers.Length / 2; i++) fftResult[i] = Math.Sqrt(complexNumbers[i].Real * complexNumbers[i].Real + complexNumbers[i].Imaginary * complexNumbers[i].Imaginary);
GetFFTFrequencyIndex(int frequency) - Gets the index in the FFT data buffer for a given frequency.
Edit:
I already added the SampleGrabber and integrated it's callback with the GetFFTData (which is still not tested). But how do integrate the GetFFTFrequencyIndex method?
protected int SampleCB(double SampleTime, IMediaSample pSample)
{
IntPtr pointer = IntPtr.Zero;
pSample.GetPointer(out pointer);
sampleDataBytes = new byte[pSample.GetSize()];
Marshal.Copy(pointer, sampleDataBytes, 0, sampleDataBytes.Length);
var sampleTime = SampleTime;
var actualDataLength = pSample.GetActualDataLength();
/* Release unmanaged resources */
Marshal.ReleaseComObject(pSample);
pSample = null;
return (int)HResults.S_OK;
}
#region ISpectrumPlayer
byte[] sampleDataBytes = null;
public bool GetFFTData(float[] fftDataBuffer)
{
if (sampleDataBytes != null)
{
var sampleData = Utils.GetInt16Array(sampleDataBytes);
double[] pRealIn = new double[sampleData.Length];
for (var i = 0; i <= sampleData.Length - 1; i++)
pRealIn[i] = sampleData[i];
var pImagIn = new double[sampleDataBytes.Length];
var pRealOut = new double[sampleDataBytes.Length];
var pImagOut = new double[sampleDataBytes.Length];
FFTUtils.Compute((uint) pRealIn.Length, pRealIn, pImagIn, pRealOut, pImagOut, false);
fftDataBuffer = new float[sampleDataBytes.Length];
for (int i = 0; i < pRealOut.Length; i++)
fftDataBuffer[i] = (float) Math.Sqrt(pRealOut[i] * pRealOut[i] + pImagOut[i] * pImagOut[i]);
}
return true;
}
public int GetFFTFrequencyIndex(int frequency)
{
throw new NotImplementedException();
}
#endregion
I ודקג this class with methods that can help:
public class FFTUtils
{
public const Double DDC_PI = 3.14159265358979323846;
/// <summary>
/// Verifies a number is a power of two
/// </summary>
/// <param name="x">Number to check</param>
/// <returns>true if number is a power two (i.e.:1,2,4,8,16,...)</returns>
public static Boolean IsPowerOfTwo(UInt32 x)
{
return ((x != 0) && (x & (x - 1)) == 0);
}
/// <summary>
/// Get Next power of number.
/// </summary>
/// <param name="x">Number to check</param>
/// <returns>A power of two number</returns>
public static UInt32 NextPowerOfTwo(UInt32 x)
{
x = x - 1;
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x + 1;
}
/// <summary>
/// Get Number of bits needed for a power of two
/// </summary>
/// <param name="PowerOfTwo">Power of two number</param>
/// <returns>Number of bits</returns>
public static UInt32 NumberOfBitsNeeded(UInt32 PowerOfTwo)
{
if (PowerOfTwo > 0)
{
for (UInt32 i = 0, mask = 1; ; i++, mask <<= 1)
{
if ((PowerOfTwo & mask) != 0)
return i;
}
}
return 0; // error
}
/// <summary>
/// Reverse bits
/// </summary>
/// <param name="index">Bits</param>
/// <param name="NumBits">Number of bits to reverse</param>
/// <returns>Reverse Bits</returns>
public static UInt32 ReverseBits(UInt32 index, UInt32 NumBits)
{
UInt32 i, rev;
for (i = rev = 0; i < NumBits; i++)
{
rev = (rev << 1) | (index & 1);
index >>= 1;
}
return rev;
}
/// <summary>
/// Return index to frequency based on number of samples
/// </summary>
/// <param name="Index">sample index</param>
/// <param name="NumSamples">number of samples</param>
/// <returns>Frequency index range</returns>
public static Double IndexToFrequency(UInt32 Index, UInt32 NumSamples)
{
if (Index >= NumSamples)
return 0.0;
else if (Index <= NumSamples / 2)
return (double)Index / (double)NumSamples;
return -(double)(NumSamples - Index) / (double)NumSamples;
}
/// <summary>
/// Compute FFT
/// </summary>
/// <param name="NumSamples">NumSamples Number of samples (must be power two)</param>
/// <param name="pRealIn">Real samples</param>
/// <param name="pImagIn">Imaginary (optional, may be null)</param>
/// <param name="pRealOut">Real coefficient output</param>
/// <param name="pImagOut">Imaginary coefficient output</param>
/// <param name="bInverseTransform">bInverseTransform when true, compute Inverse FFT</param>
public static void Compute(UInt32 NumSamples, Double[] pRealIn, Double[] pImagIn,
Double[] pRealOut, Double[] pImagOut, Boolean bInverseTransform)
{
UInt32 NumBits; /* Number of bits needed to store indices */
UInt32 i, j, k, n;
UInt32 BlockSize, BlockEnd;
double angle_numerator = 2.0 * DDC_PI;
double tr, ti; /* temp real, temp imaginary */
if (pRealIn == null || pRealOut == null || pImagOut == null)
{
// error
throw new ArgumentNullException("Null argument");
}
if (!IsPowerOfTwo(NumSamples))
{
// error
throw new ArgumentException("Number of samples must be power of 2");
}
if (pRealIn.Length < NumSamples || (pImagIn != null && pImagIn.Length < NumSamples) ||
pRealOut.Length < NumSamples || pImagOut.Length < NumSamples)
{
// error
throw new ArgumentException("Invalid Array argument detected");
}
if (bInverseTransform)
angle_numerator = -angle_numerator;
NumBits = NumberOfBitsNeeded(NumSamples);
/*
** Do simultaneous data copy and bit-reversal ordering into outputs...
*/
for (i = 0; i < NumSamples; i++)
{
j = ReverseBits(i, NumBits);
pRealOut[j] = pRealIn[i];
pImagOut[j] = (double)((pImagIn == null) ? 0.0 : pImagIn[i]);
}
/*
** Do the FFT itself...
*/
BlockEnd = 1;
for (BlockSize = 2; BlockSize <= NumSamples; BlockSize <<= 1)
{
double delta_angle = angle_numerator / (double)BlockSize;
double sm2 = Math.Sin(-2 * delta_angle);
double sm1 = Math.Sin(-delta_angle);
double cm2 = Math.Cos(-2 * delta_angle);
double cm1 = Math.Cos(-delta_angle);
double w = 2 * cm1;
double ar0, ar1, ar2;
double ai0, ai1, ai2;
for (i = 0; i < NumSamples; i += BlockSize)
{
ar2 = cm2;
ar1 = cm1;
ai2 = sm2;
ai1 = sm1;
for (j = i, n = 0; n < BlockEnd; j++, n++)
{
ar0 = w * ar1 - ar2;
ar2 = ar1;
ar1 = ar0;
ai0 = w * ai1 - ai2;
ai2 = ai1;
ai1 = ai0;
k = j + BlockEnd;
tr = ar0 * pRealOut[k] - ai0 * pImagOut[k];
ti = ar0 * pImagOut[k] + ai0 * pRealOut[k];
pRealOut[k] = (pRealOut[j] - tr);
pImagOut[k] = (pImagOut[j] - ti);
pRealOut[j] += (tr);
pImagOut[j] += (ti);
}
}
BlockEnd = BlockSize;
}
/*
** Need to normalize if inverse transform...
*/
if (bInverseTransform)
{
double denom = (double)(NumSamples);
for (i = 0; i < NumSamples; i++)
{
pRealOut[i] /= denom;
pImagOut[i] /= denom;
}
}
}
/// <summary>
/// Calculate normal (power spectrum)
/// </summary>
/// <param name="NumSamples">Number of sample</param>
/// <param name="pReal">Real coefficient buffer</param>
/// <param name="pImag">Imaginary coefficient buffer</param>
/// <param name="pAmpl">Working buffer to hold amplitude Xps(m) = | X(m)^2 | = Xreal(m)^2 + Ximag(m)^2</param>
public static void Norm(UInt32 NumSamples, Double[] pReal, Double[] pImag, Double[] pAmpl)
{
if (pReal == null || pImag == null || pAmpl == null)
{
// error
throw new ArgumentNullException("pReal,pImag,pAmpl");
}
if (pReal.Length < NumSamples || pImag.Length < NumSamples || pAmpl.Length < NumSamples)
{
// error
throw new ArgumentException("Invalid Array argument detected");
}
// Calculate amplitude values in the buffer provided
for (UInt32 i = 0; i < NumSamples; i++)
{
pAmpl[i] = pReal[i] * pReal[i] + pImag[i] * pImag[i];
}
}
/// <summary>
/// Find Peak frequency in Hz
/// </summary>
/// <param name="NumSamples">Number of samples</param>
/// <param name="pAmpl">Current amplitude</param>
/// <param name="samplingRate">Sampling rate in samples/second (Hz)</param>
/// <param name="index">Frequency index</param>
/// <returns>Peak frequency in Hz</returns>
public static Double PeakFrequency(UInt32 NumSamples, Double[] pAmpl, Double samplingRate, ref UInt32 index)
{
UInt32 N = NumSamples >> 1; // number of positive frequencies. (numSamples/2)
if (pAmpl == null)
{
// error
throw new ArgumentNullException("pAmpl");
}
if (pAmpl.Length < NumSamples)
{
// error
throw new ArgumentException("Invalid Array argument detected");
}
double maxAmpl = -1.0;
double peakFreq = -1.0;
index = 0;
for (UInt32 i = 0; i < N; i++)
{
if (pAmpl[i] > maxAmpl)
{
maxAmpl = (double)pAmpl[i];
index = i;
peakFreq = (double)(i);
}
}
return samplingRate * peakFreq / (double)(NumSamples);
}
}
Thank you so much!
If I remember well, the algorithm takes a real (e.g. int[n]) signal or a complex one (e.g. int[n][2]) and returns a complex FFT result.
So, it seems quite easy:
You take your input values (that you can plot as value-to-time in a chart, e.g. the left speaker audio values) and you feed them in the pRealIn parameter. In pImagIn you put zeros (as many as in pRealIn). In bInverseTransform you put false (of course).
Then you will take the result back in pRealOut & pImagOut. The result buffers should logically be of the same size as the input buffers.
You must take those two output buffers and combine them in pair like so (for each element of the OUT arrays):
fftDataBuffer[k] = Math.Sqrt(pRealOut[k] * pRealOut[k] + pImagOut[k] * pImagOut[k]); // Do this from 1 to n
FFT result is an array of complex values (x = real part and y = imaginary part - you can depict it on a Cartesian system as a vector). You want the vector's size/amplitude that why you do the above.
That is for GetFFTData.
I see that you have a function called IndexToFrequency. So that may work.
All you have to do is call this method for every index of your buffers. That is:
for(int i=0; i<n; i++) freq[i] = IndexToFrequency(i, n);
Keep those values stored and then in your GetFFTFrequencyIndex(int frequency) you find the closest match of the input parameter (frequency) to the elements in freq[n] and return its index.
I think that will be enough.
Important: Make sure that your buffers have a power-of-two size (NextPowerOfTwo seems to be designed to help you do just that).
If your data happens to be smaller some times, you can pad the values with zeros at the end (a.k.a. append zeros to your input buffers).
Also: To get a better resolution you can again pad with zeros your data. This will increase the 'smoothness' of your result which may be desirable.
Where did you find this code, if I may ask (just curious :) )?
So, that's all it! :)
I don't know it my nomenclature is correct! Anyway, these are the integer I have, for example :
76
121
9660
And I'd like to round them to the close hundred, such as they must become :
100
100
9700
How can I do it faster in C#? I think about an algorithm, but maybe there are some utilities on C#?
Try the Math.Round method. Here's how:
Math.Round(76d / 100d, 0) * 100;
Math.Round(121d / 100d, 0) * 100;
Math.Round(9660d / 100d, 0) * 100;
I wrote a simple extension method to generalize this kind of rounding a while ago:
public static class MathExtensions
{
public static int Round(this int i, int nearest)
{
if (nearest <= 0 || nearest % 10 != 0)
throw new ArgumentOutOfRangeException("nearest", "Must round to a positive multiple of 10");
return (i + 5 * nearest / 10) / nearest * nearest;
}
}
It leverages integer division to find the closest rounding.
Example use:
int example = 152;
Console.WriteLine(example.Round(100)); // round to the nearest 100
Console.WriteLine(example.Round(10)); // round to the nearest 10
And in your example:
Console.WriteLine(76.Round(100)); // 100
Console.WriteLine(121.Round(100)); // 100
Console.WriteLine(9660.Round(100)); // 9700
Try this expression:
(n + 50) / 100 * 100
Caveat: only works for non-negative n.
Just some addition to #krizzzn's accepted answer...
Do note that the following will return 0:
Math.Round(50d / 100d, 0) * 100;
Consider using the following and make it return 100 instead:
Math.Round(50d / 100d, 0, MidpointRounding.AwayFromZero) * 100;
Depending on what you're doing, using decimals might be a better choice (note the m):
Math.Round(50m / 100m, 0, MidpointRounding.AwayFromZero) * 100m;
I know this is an old thread. I wrote a new method. Hope this will be useful for some one.
public static double Round(this float value, int precision)
{
if (precision < -4 && precision > 15)
throw new ArgumentOutOfRangeException("precision", "Must be and integer between -4 and 15");
if (precision >= 0) return Math.Round(value, precision);
else
{
precision = (int)Math.Pow(10, Math.Abs(precision));
value = value + (5 * precision / 10);
return Math.Round(value - (value % precision), 0);
}
}
Example:
float value = 6666.677777F;
Console.Write(value.Round(2)); //6666.68
Console.Write(value.Round(0)); //6667
Console.Write(value.Round(-2)); //6700
Hi i write this extension this gets the next hundred for each number you pass
/// <summary>
/// this extension gets the next hunfìdred for any number you whant
/// </summary>
/// <param name="i">numeber to rounded</param>
/// <returns>the next hundred number</returns>
/// <remarks>
/// eg.:
/// i = 21 gets 100
/// i = 121 gets 200
/// i = 200 gets 300
/// i = 1211 gets 1300
/// i = -108 gets -200
/// </remarks>
public static int RoundToNextHundred(this int i)
{
return i += (100 * Math.Sign(i) - i % 100);
//use this line below if you want RoundHundred not NEXT
//return i % 100 == byte.MinValue? i : i += (100 * Math.Sign(i) - i % 100);
}
//and for answer at title point use this algoritm
var closeHundred = Math.Round(number / 100D)*100;
//and here the extension method if you prefer
/// <summary>
/// this extension gets the close hundred for any number you whant
/// </summary>
/// <param name="number">number to be rounded</param>
/// <returns>the close hundred number</returns>
/// <remarks>
/// eg.:
/// number = 21 gets 0
/// number = 149 gets 100
/// number = 151 gets 200
/// number = -149 gets -100
/// number = -151 gets -200
/// </remarks>
public static int RoundCloseHundred(this int number)
{
return (int)Math.Round(number / 100D) * 100;
}
If you only want to round integer numbers up (as the OP actually did), then you can resort to this solution:
public static class MathExtensions
{
public static int RoundUpTo(this int number, int nearest)
{
if (nearest < 10 || nearest % 10 != 0)
throw new ArgumentOutOfRangeException(nameof(nearest), $"{nameof(nearest)} must be a positive multiple of 10, but you specified {nearest}.");
int modulo = number % nearest;
return modulo == 0 ? number : modulo > 0 ? number + (nearest - modulo) : number - modulo;
}
}
If you want to perform floating-point (or decimal) rounding, then resort to the answers of #krizzzn and #Jim Aho.
int num = 9660;
int remainder = num % 100;
Console.WriteLine(remainder < 50 ? num - remainder : num + (100 -remainder));
Note: I haven't tested this thoroughly.
I had a similar project internally where the business requirements were to search within the 100's range of a given number and find duplicate DB records. So if the user was using line 856 I would search 800 - 899. If the user was using 8567 I would search 8500 - 8599. Not an exact rounding by 100's, but thought I would include my unique approach as some of these basic coding questions are embedded within a larger business project. To test this I seeded a decimal list from 1 - 99999 and spit the results out into a file.
/// <summary>
/// This method accepts an inbound Line Number and returns the line range
/// in the form of lowest to highest based on 100's
/// Example would be 9122 returns 9100 - 9199
/// It's used for generating some additional BOM Temp functionality.
/// </summary>
/// <param name="inboundNumber"></param>
/// <returns></returns>
public static ProjectLineRange CalculateLineRange(decimal inboundNumber)
{
var lineRange = new ProjectLineRange();
var numberLength = inboundNumber.ToString(CultureInfo.InvariantCulture).Length;
switch (numberLength)
{
case 0: //NULL?
break;
case 1: //Represents 1 - 9
lineRange.LineBottom = 1;
lineRange.LineTop = 99;
break;
case 2: //Represents 10 - 99
lineRange.LineBottom = 1;
lineRange.LineTop = 99;
break;
case 3: //Represents 100 - 999
lineRange = CalculateHundredsRange((int)(inboundNumber / 100));
break;
case 4: //Represents 1000 - 9999
lineRange = CalculateThousandsRange(
Convert.ToInt32(inboundNumber.ToString(CultureInfo.InvariantCulture).Substring(1, 1)),
Convert.ToInt32(inboundNumber.ToString(CultureInfo.InvariantCulture).Substring(0, 1)));
break;
case 5: //Represents 10000 - 99999
lineRange = CalculateTenThousandsRange(
Convert.ToInt32(inboundNumber.ToString(CultureInfo.InvariantCulture).Substring(2, 1)),
Convert.ToInt32(inboundNumber.ToString(CultureInfo.InvariantCulture).Substring(1, 1)),
Convert.ToInt32(inboundNumber.ToString(CultureInfo.InvariantCulture).Substring(0, 1)));
break;
}
return lineRange;
}
public class ProjectLineRange
{
public decimal LineBottom { get; set; }
public decimal LineTop { get; set; }
}
/// <summary>
/// Helper method to return the range for the 100's place
/// </summary>
/// <param name="hundredsPlaceValue"></param>
/// <returns></returns>
public static ProjectLineRange CalculateHundredsRange(int hundredsPlaceValue)
{
var tempLineRange = new ProjectLineRange();
tempLineRange.LineBottom = hundredsPlaceValue * 100;
tempLineRange.LineTop = tempLineRange.LineBottom + 99;
return tempLineRange;
}
/// <summary>
/// Helper method to return the range for the 100's place when factoring a 1000's number
/// </summary>
/// <param name="hundredsPlaceValue"></param>
/// <param name="thousandsPlaceValue"></param>
/// <returns></returns>
public static ProjectLineRange CalculateThousandsRange(int hundredsPlaceValue, int thousandsPlaceValue)
{
var tempLineRange = new ProjectLineRange();
var tempThousands = thousandsPlaceValue * 1000;
var hundredsRange = CalculateHundredsRange(hundredsPlaceValue);
tempLineRange.LineBottom = tempThousands + hundredsRange.LineBottom;
tempLineRange.LineTop = tempThousands + hundredsRange.LineTop;
return tempLineRange;
}
/// <summary>
/// Helper method to return the range for the 100's place when factoring a 10000's number
/// </summary>
/// <param name="hundredsPlaceValue"></param>
/// <param name="thousandsPlaceValue"></param>
/// <param name="tenThousandsPlaceValue"></param>
/// <returns></returns>
public static ProjectLineRange CalculateTenThousandsRange(int hundredsPlaceValue, int thousandsPlaceValue, int tenThousandsPlaceValue)
{
var tempLineRange = new ProjectLineRange();
var tempThousands = thousandsPlaceValue * 1000;
var tempTenThousands = tenThousandsPlaceValue * 10000;
var hundredsRange = CalculateHundredsRange(hundredsPlaceValue);
tempLineRange.LineBottom = tempTenThousands + tempThousands + hundredsRange.LineBottom;
tempLineRange.LineTop = tempTenThousands + tempThousands + hundredsRange.LineTop;
return tempLineRange;
}
public static class Maths
{
public static int Round(this int value, int precision)
{
var coef = Math.Pow(10, Math.Abs(precision));
var x = (int)Math.Round(value / coef, 0);
return x * (int)coef;
}
}
var number = 34569;
Debug.WriteLine(number.Round(0));//34569
Debug.WriteLine(number.Round(1));//34570
Debug.WriteLine(number.Round(2));//34600
Debug.WriteLine(number.Round(3));//35000
Debug.WriteLine(number.Round(4));//30000
Debug.WriteLine(number.Round(5));// 0
Debug.WriteLine(number.Round(6));// 0
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I want to generate folders using combinations of given characters
i.e. 8 character text with combination of characters: abcdefghijklmnopqrstuvwxyz1234567890.
For the 8 characters combinations there are 2821109907456 possibilities. I want to group these by range of 10,000.
I need to put these folders in relevant range folders i.e.
'aaaaaaa1 - aaaaaaa9' is a range of 9 combinations and a folder 'aaaaaaa3' will be created in this range folder.
I want to use c# code, give my method a folder name i.e. 'aaaaaaa3' and be returned the relevant folder range i.e. 'aaaaaa1 - aaaaaaa9' where it should be saved.
Question: I need c# code to do this!
You are actually using 36-base notation (36 digits are used to represent numbers).
So the easiest way to handle these filenames is to convert them to decimal notation and then just divide by 10000.
Something like this:
string alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
string fileName = "asdjg66";
long result = 0;
foreach (var c in fileName)
{
sum = sum * 36 + alphabet.IndexOf(c);
}
And use sum to determine the target range. Just convert sum / 10000 back to 36-base notation. And you are done.
From the beginning, it looks like we're going to need to compute ranges of alphanumeric sequences, which means converting them to numbers and back. An all-purpose base converter seems like the first logical step:
/// <summary>
/// Provides conversion between long integers and custom number bases.
/// </summary>
public class BaseConverter
{
private string _characterSet;
/// <summary>
/// Creates a new BaseConverter.
/// </summary>
/// <param name="characterSet">The characters in the custom base, in
/// increasing order of value.</param>
public BaseConverter(string characterSet =
"0123456789abcdefghijklmnopqrstuvwxyz")
{
_characterSet = characterSet;
}
/// <summary>
/// Converts a number in the custom base system to a long.
/// </summary>
/// <param name="value">The custom base number to convert.</param>
/// <returns>The long form of the custom base number.</returns>
public long StringToLong(string value)
{
if (value == Convert.ToString(_characterSet[0])) return 0;
long val = 0;
string text = value[0] == '-' ? value.Substring(1,
value.Length - 1) : value;
for (int i = text.Length, power = 0; i != 0; i--, power++)
{
val += (long)Math.Round((_characterSet.IndexOf(text[i-1]) *
Math.Pow(_characterSet.Length, power)));
}
return value[0] == '-' ? -val : val;
}
/// <summary>
/// Converts a long to the custom base system.
/// </summary>
/// <param name="value">The long to convert.</param>
/// <returns>The custome base number version of the long.</returns>
public string LongToString(long value)
{
if (value == 0) return Convert.ToString(_characterSet[0]);
long number = value.Abs();
int remainder;
StringBuilder text = new StringBuilder((int)Math.Round(
Math.Log(long.MaxValue, (double)_characterSet.Length)) +
value < 0 ? 1 : 0);
while (number != 0)
{
remainder = (int)(number % _characterSet.Length);
text.Insert(0, _characterSet[remainder]);
number -= remainder;
number /= _characterSet.Length;
}
if (value < 0) text.Insert(0, "-");
return text.ToString();
}
Then, you'll need the code to compute your ranges:
///<summary>
///Computes numeric ranges using a BaseConverter.
///</summary>
public class NumericRangeFactory
{
private long _min, _length;
private BaseConverter _converter;
//creates a new NumericRangeFactory
//converter - the BaseConverter that defines the number system
//being used
//min - the smallest value in an acceptable range
//length - the number of values in a single range
public NumericRangeFactory(BaseConverter converter, long min,
long length)
{
_converter = converter; _min = min; _length = length;
}
public NumericRangeFactory(BaseConverter converter, string min,
long length) : this(converter.StringToLong(min), length) {}
//returns an array of long containing the min and max of the
//range that contains value
public long[] GetLongRange(long value)
{
long min = _length * (value / _length); //todo: fix non-zero _min case
return new long[] { min, min + length - 1 };
}
public long[] GetLongRange(string value)
{
return GetLongRange(_converter.StringToLong(value));
}
//returns an array of string containing the min and max of
//the range that contains value
public string[] GetStringRange(long value)
{
long[] range = GetLongRange(value);
return new string[] {_converter.LongToString(range[0]),
_converter.LongToString(range[1])};
}
public string[] GetStringRange(string value)
{
return GetStringRange(_converter.StringToLong(value));
}
}
Finally, tie the BaseConverter and NumericRangeFactory classes together to solve the problem with this sample static method:
public static string GetFolderRange(string folderName)
{
BaseConverter converter = new BaseConverter();
NumericRangeFactory rangeFactory = new NumericRangeFactory(converter,
"aaaaaaa0", 9);
string[] range = rangeFactory.GetStringRange(folderName);
return range[0] + "-" + range[1];
}
I haven't tested this, but I think the concept is solid.
string getRange(string fileName) {
string prefix = fileName.Substring(0, 7);
string start = "a";
string end = "0";
return prefix + start + " - " + prefix + end;
}
To make the range larger, most easily in powers of 36, make the prefix shorter and make the start and end repeat themselves a few times: (0, 6)..."aa"..."00". To make the range shorter, do something like this:
const string values = "abcdefghijklmnopqrstuvwxyz1234567890";
Then:
int index = values.IndexOf(fileName[7]);
if (index < 12) {
start = "a";
end = "l";
} else if (index < 24) ...