Related
This question already has answers here:
Get `n` random values between 2 numbers having average `x`
(5 answers)
Closed 6 years ago.
Problem: Getting a set of random numbers between two values that will have a certain mean value.
Let say we getting n number of random number where the number will be between 1 and 100. We have a mean of 25.
My first approach is to have 2 modes where we have aboveMean and belowMean where the first random number is the initial range 1 and 100. Every subsequent number will check the total sum. If the total sum is above the mean, we go to case aboveMean which is then get a random number between 1 and 25. If the total sum is below the mean, we do case belowMean then get a random number between 26 and 100.
I need some idea on how to approach this problem beside the crude get a random number to add it to the total then get the average. If it above the mean in question, we get a random number below the mean and so forth. While it does work, doesn't seem to be the best method.
I'm guessing I should brush up on probability to approach this random number generator.
Let us divide the range into left and right portions. Use a value from the portion at a frequency corresponding to the relative width of the other half.
int Leruce_rand(int min, int mean, int max) {
int r = rand()%(max - min + 1);
if (r < mean) {
// find number in right half
return rand()%(max - mean + 1) + mean;
} else {
// find number in left half
return rand()%(mean - min) + min;
}
Assumes mean is part of the right half. This quick solution likely has small bias.
Given OP's values, roughly, the average of the left half is 12.5 and called 75% of the time. Average of the right is 62.5 called 25% of the time: average 25.
This approach differs from OP's which "Every subsequent number will check the total sum. If the total sum is above the mean, we go to case aboveMean which is then get a random number between 1 and 25." As that absolutely prevents a set of occurrences above or below the mean. With RNG, the value generated should not be biased on the history of previous generated values.
There's literally an infinite number of ways to achieve this. For instance, generate 3 random numbers between 1 and 100 (std::uniform_int_distribution) and take the minimum of those (std::min(a,b,c)).
Obviously, for a mean of 75 you'll need to pick the maximum of 3 numbers.
The benefit of this method is that each outcome is independent of the previous ones. It's completely random.
Take some good distribution and use it. Say, Binomial distribution. Use B(99,24/99),
so sampled values are in the range 0...99, with parameter p equal to 24/99.
So if you have routine which sample from B, then all you need is to add 1
to be in he range 1...100
Mean value for binomial would be p*n, in this case equal to 24. Because you're adding 1, your mean value would be 25 as required. C++11 has binomial RNG in the
standard library
Some code (not tested)
#include <iostream>
#include <random>
int main() {
std::default_random_engine generator;
std::binomial_distribution<int> distribution(99, double(24)/double(99));
for (int i=0; i != 1000; ++i) {
int number = distribution(generator) + 1;
std::cout << number << std::endl;
}
return 0;
}
Assume a fair random(a,b) function (this question should not be about which random function is better) then simply just restrcting ithe ranges that is piced from should be a good start, like;
const int desiredCount = 16;
const int deiredMean = 25;
int sumValues = random(a,b);
int count = 1;
while (count < desriredCount - 1) {
int mean = sumValue/count;
int nextValue = 0;
if (mean < desiredMean) // Too small, reduce probablity of smaller numbers
nextValue = random(a+(desiredMean-mean)/(desriredCount-count),b);
else //too large, reduce probability of larger numbers
nextValue = random(a,b-(mean-desiredMean)/(desriredCount-count));
sumValue += nextValue;
count += 1;
}
int lastValue = desiredMean*desriredCount - sumValue/count;
sumValue += lastValue;
count += 1;
Note: The above is not tested, and my thinking is that the trimming of the upper and lower bound may not be sufficently aggressive to do the trick, but I hope that i will get you going.
Some boundary conditions, such as if you only want 2 numbers and a means of 25 from numbers between 0 and 100, the initial random number cannot be larger than 50, since that makes it impossible to pick the second (last) number -- so if you want the algo to give you exact mean values under all circumstances, then a bit more tweaking is needed.
OP's wants a set of numbers meeting certain criteria.
Consider generating all possible sets of n numbers in the range [min max] and then eliminating all sets but those with the desired mean. Now randomly select one of those sets. This would meet OP's goal and IMO would pass fair randomness tests. Yet this direct approach is potentially a huge task.
Alternatively, randomly generate lots of sets until one is found that meets the mean test.
The below meets OP's requirement of a specified mean without directly biasing the random numbers selected. Certainly not an efficient method when the desired mean is far from the min/max average.
#include <stdio.h>
#include <stdlib.h>
void L_set(int *set, size_t n, int min, int mean, int max) {
assert(n > 0);
assert(min >= 0);
assert(mean >= min);
assert(max >= mean);
size_t i;
long long diff;
long long sum_target = n;
unsigned long long loop = 0;
sum_target *= mean;
int range = max - min + 1;
do {
loop++;
long long sum = 0;
for (i = 1; i < n; i++) {
set[i] = rand() % range + min;
sum += set[i];
}
diff = sum_target - sum; // What does the final number need to be?
} while (diff < min || diff > max);
set[0] = (int) diff;
printf("n:%zu min:%d mean:%2d max:%3d loop:%6llu {", n, min, mean, max, loop);
for (i = 0; i < n; i++) {
printf("%3d,", set[i]);
}
printf("}\n");
fflush(stdout);
}
int main(void) {
int set[1000];
L_set(set, 10, 1, 2, 4);
L_set(set, 16, 1, 50, 100);
L_set(set, 16, 1, 25, 100);
L_set(set, 16, 1, 20, 100);
return 0;
}
Output
n:10 min:1 mean: 2 max: 4 loop: 1 { 4, 2, 4, 3, 2, 1, 1, 1, 1, 1,}
n:16 min:1 mean:50 max:100 loop: 2 { 45, 81, 24, 50, 93, 65, 70, 52, 28, 91, 25, 36, 21, 45, 11, 63,}
n:16 min:1 mean:25 max:100 loop: 3257 { 52, 1, 15, 70, 66, 30, 1, 4, 26, 1, 16, 4, 48, 42, 19, 5,}
n:16 min:1 mean:20 max:100 loop:192974 { 24, 10, 13, 3, 3, 53, 22, 12, 29, 1, 7, 6, 90, 11, 20, 16,}
you have to go into some probabilities theory. there are a lot of methods to judge on random sequence. for example if you lower the deviation you will get triangle-looking-on-a-graph sequence, which can in the end be proven not trully random. so there is not really much choice than getting random generator and discarding the sequences you don't like.
EDIT: this generates numbers in the range 1..100 with a theoretical mean of 25.25. It does this by using a random modulus in the range 1..100. Note that the required mean is 25, which is not exactly a quarter of the range 1..100.
OP wanted a way of varying the next number chosen according to whether the mean is less than or more than 25, but that lends some predictabilty - if the mean is more than 25 then you know the next "random" number will be less than 25.
The random calculation in the code is a very simple one line.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define RUNS 10000000
#define MAXN 100
int main() {
int n, i, sum = 0, min = MAXN, max = 0;
int freq[MAXN+1] = {0};
srand((unsigned)time(NULL));
for(i = 0; i < RUNS; i++) {
n = 1 + rand() % (1 + rand() % 100); // average modulus is (1 + MAX) / 2
if(max < n) {
max = n; // check that whole range is picked
}
if(min > n) {
min = n;
}
freq[n]++; // keep a tally
sum += n;
}
// show statistis
printf("Mean = %f, min = %d, max = %d\n", (double)sum / RUNS, min, max);
for(n = MAXN; n > 0; n--) {
printf("%3d ", n);
for(i = (freq[n] + 5000) / 10000; i > 0; i--) {
printf("|");
}
printf("\n");
}
return 0;
}
Program output showing distribution / 10000:
Mean = 25.728128, min = 1, max = 100
100
99
98
97
96 |
95 |
94 |
93 |
92 |
91 |
90 |
89 |
88 |
87 |
86 ||
85 ||
84 ||
83 ||
82 ||
81 ||
80 ||
79 ||
78 |||
77 |||
76 |||
75 |||
74 |||
73 |||
72 |||
71 ||||
70 ||||
69 ||||
68 ||||
67 ||||
66 ||||
65 ||||
64 |||||
63 |||||
62 |||||
61 |||||
60 |||||
59 |||||
58 ||||||
57 ||||||
56 ||||||
55 ||||||
54 ||||||
53 ||||||
52 |||||||
51 |||||||
50 |||||||
49 |||||||
48 |||||||
47 ||||||||
46 ||||||||
45 ||||||||
44 ||||||||
43 |||||||||
42 |||||||||
41 |||||||||
40 |||||||||
39 ||||||||||
38 ||||||||||
37 ||||||||||
36 ||||||||||
35 |||||||||||
34 |||||||||||
33 |||||||||||
32 ||||||||||||
31 ||||||||||||
30 ||||||||||||
29 |||||||||||||
28 |||||||||||||
27 |||||||||||||
26 ||||||||||||||
25 ||||||||||||||
24 ||||||||||||||
23 |||||||||||||||
22 |||||||||||||||
21 ||||||||||||||||
20 ||||||||||||||||
19 |||||||||||||||||
18 |||||||||||||||||
17 ||||||||||||||||||
16 |||||||||||||||||||
15 |||||||||||||||||||
14 ||||||||||||||||||||
13 |||||||||||||||||||||
12 ||||||||||||||||||||||
11 |||||||||||||||||||||||
10 ||||||||||||||||||||||||
9 |||||||||||||||||||||||||
8 ||||||||||||||||||||||||||
7 |||||||||||||||||||||||||||
6 |||||||||||||||||||||||||||||
5 |||||||||||||||||||||||||||||||
4 |||||||||||||||||||||||||||||||||
3 |||||||||||||||||||||||||||||||||||||
2 ||||||||||||||||||||||||||||||||||||||||||
1 ||||||||||||||||||||||||||||||||||||||||||||||||||||
OP did not state what kind of distribution was wanted, for example two straight lines pivoting at 25, or perhaps equal distribution each side of 25. However this solution is very simple to implement.
I have three integer variables, that can take only the values 0, 1 and 2. I want to distinguish what combination of all three numbers I have, ordering doesn't count. Let's say the variables are called x, y and z. Then x=1, y=0, z=0 and x=0, y=1, z=0 and x=0, y=0, z=1 are all the same number in this case, I will refer to this combination as 001.
Now there are a hundred ways how to do this, but I am asking for an elegant solution, be it only for educational purposes.
I thought about bitwise shifting 001 by the amount of the value:
001 << 0 = 1
001 << 1 = 2
001 << 2 = 4
But then the numbers 002 and 111 would both give 6.
The shift idea is good, but you need 2 bits to count to 3. So try shifting by twice the number of bits:
1 << (2*0) = 1
1 << (2*1) = 4
1 << (2*2) = 16
Add these for all 3 numbers, and the first 2 bits will count how many 0 you have, the second 2 bits will count how many 1 and the third 2 bits will count how many 2.
Edit although the result is 6 bit long (2 bits per number option 0,1,2), you only need the lowest 4 bits for a unique identifier - as if you know how many 0 and 1 you have, then the number of 2 is determined also.
So instead of doing
res = 1<<(2*x);
res+= 1<<(2*y);
res+= 1<<(2*z);
you can do
res = x*x;
res+= y*y;
res+= z*z;
because then
0*0 = 0 // doesn't change result. We don't count 0
1*1 = 1 // we count the number of 1 in the 2 lower bits
2*2 = 4 // we count the number of 2 in the 2 higher bits
hence using only 4 bits instead of 6.
When the number of distinct possibilities is small, using a lookup table could be used.
First, number all possible combinations of three digits, like this:
Combinations N Indexes
------------- - ------
000 0 0
001, 010, 100 1 1, 3, 9
002, 020, 200 2 2, 6, 18
011, 101, 110 3 4, 10, 12
012, 021, 102, 120, 201, 210 4 5, 7, 11, 15, 19, 21
022, 202, 220 5 8, 20, 24
111 6 13
112, 121, 211 7 14, 16, 22
122, 212, 221 8 17, 23, 25
222 9 26
The first column shows identical combinations; the second column shows the number of the combination (I assigned them arbitrarily); the third column shows the indexes of each combination, computed as 9*<first digit> + 3*<second digit> + <third digit>.
Next, build a look-up table for each of these ten combinations, using this expression as an index:
9*a + 3*b + c
where a, b, and c are the three numbers that you have. The table would look like this:
int lookup[] = {
0, 1, 2, 1, 3, 4, 2, 4, 5, 1
, 3, 4, 3, 6, 7, 4, 7, 8, 2, 4
, 5, 4, 7, 8, 5, 8, 9
};
This is a rewrite of the first table, with values at the indexes corresponding to the value in the column N. For example, combination number 1 is founds at indexes 1, 3, and 9; combination 2 is at indexes 2, 6, and 18, and so on.
To obtain the number of the combination, simply check
int combNumber = lookup[9*a + 3*b + c];
For such small numbers, it would be easiest to just check them individually, instead of trying to be fancy, eg:
bool hasZero = false;
bool hasOne = false;
bool hasTwo = false;
// given: char* number or char[] number...
for(int i = 0; i < 3; ++i)
{
switch (number[i])
{
case '0': hasZero = true; break;
case '1': hasOne = true; break;
case '2': hasTwo = true; break;
default: /* error! */ break;
}
}
If I understand you correctly, you have some sequence of numbers that can either be 1, 2, or 3, where the permutation of them doesn't matter (just the different combinations).
That being the case:
std::vector<int> v{1, 2, 3};
std::sort(v.begin(), v.end());
That will keep all of the different combinations properly aligned, and you could easily write a loop to test for equality.
Alternatively, you could use a std::array<int, N> (where N is the number of possible values - in this case 3).
std::array<int, 3> a;
Where you would set a[0] equal to the number of 1s you have, a[1] equal to the number of '2's, etc.
// if your string is 111
a[0] = 3;
// if your string is 110 or 011
a[0] = 2;
// if your string is 100 or 010 or 001
a[0] = 1;
// if your string is 120
a[0] = 1;
a[1] = 1;
// if your string is 123
a[0] = 1;
a[1] = 1;
a[2] = 1;
If you are looking to store it in a single 32-bit integer:
unsigned long x = 1; // number of 1's in your string
unsigned long y = 1; // number of 2's in your string
unsigned long z = 1; // number of 3's in your string
unsigned long result = x | y << 8 | z << 16;
To retrieve the number of each, you would do
unsigned long x = result & 0x000000FF;
unsigned long y = (result >> 8) & 0x000000FF;
unsigned long z = (result >> 16) & 0x000000FF;
This is very similar to what happens in the RBG macros.
int n[3]={0,0,0};
++n[x];
++n[y];
++n[z];
Now, in the n array, you have a unique ordered combination of values for each unique unordered combination of x,y,z.
For example, both x=1,y=0,z=0 and x=0,y=0,z=1 will give you n={2,1,0}
I'm trying to encode a relatively complex message into a union structure so that I can generate an array of uint8_t that I can feed into a serial communications protocol.
However, when looking at the array generated when my union is filled with data, an extra uint8_t element appears after my command type element. Please see the Union structure below:
union myint16_t{
uint16_t ui16;
int16_t i16;
uint8_t data[2];
};
union {
struct {
uint8_t commandtype;
myint16_t UpperLimits[4];
myint16_t LowerLimits[4];
myint16_t JointZeros[4];
int8_t JointPolarity[4];
myint16_t P[4];
myint16_t I[4];
myint16_t D[4];
};
uint8_t data[53];
};
as you can see there are the second anonymous union references the union myint16_t.
So if I fill all the values of the anonymous union and then print out the underlying data[53] array, my second value (data[1]) is 0 and not part of the first element of UpperLimits[4]. Please see the code where I fill the union and then print out the elements.
char q = 'c';
hmmv4_configmsg msg;
msg.commandtype =(uint8_t) q;
msg.UpperLimits[0].ui16 = 784;
msg.UpperLimits[1].ui16 = 784;
msg.UpperLimits[2].ui16 = 784;
msg.UpperLimits[3].ui16 = 784;
msg.LowerLimits[0].ui16 = 223;
msg.LowerLimits[1].ui16 = 223;
msg.LowerLimits[2].ui16 = 223;
msg.LowerLimits[3].ui16 = 223;
msg.JointZeros[0].ui16 = 512;
msg.JointZeros[1].ui16 = 512;
msg.JointZeros[2].ui16 = 512;
msg.JointZeros[3].ui16 = 512;
msg.JointPolarity[0] = -1;
msg.JointPolarity[1] =-1;
msg.JointPolarity[2] =-1;
msg.JointPolarity[3] =-1;
msg.P[0].i16=4000;
msg.P[1].i16=4000;
msg.P[2].i16=4000;
msg.P[3].i16=4000;
msg.I[0].i16=1;
msg.I[1].i16=1;
msg.I[2].i16=1;
msg.I[3].i16=1;
msg.D[0].i16=24;
msg.D[1].i16=24;
msg.D[2].i16=24;
msg.D[3].i16=24;
//msg.change_endian();
while(1)
{
for(int i =0; i<54; i++)
{
writebuf[i]=msg.data[i];
printf("D: %d, %d \n", i, msg.data[i]);
}
printf("L0: %d, %d, %d", msg.P[0].i16, msg.P[0].data[0], msg.P[0].data[1]);
int r =jointencoder.xfer1(writebuf, readbuf, 54);
}
the output of the printf is (the offending element is D:1 -- it shouldn't be there):
D: 0, 99
D: 1, 0
D: 2, 16
D: 3, 3
D: 4, 16
D: 5, 3
D: 6, 16
D: 7, 3
D: 8, 16
D: 9, 3
D: 10, 223
D: 11, 0
D: 12, 223
D: 13, 0
D: 14, 223
D: 15, 0
D: 16, 223
D: 17, 0
D: 18, 0
D: 19, 2
D: 20, 0
D: 21, 2
D: 22, 0
D: 23, 2
D: 24, 0
D: 25, 2
D: 26, 255
D: 27, 255
D: 28, 255
D: 29, 255
D: 30, 160
D: 31, 15
D: 32, 160
D: 33, 15
D: 34, 160
D: 35, 15
D: 36, 160
D: 37, 15
D: 38, 1
D: 39, 0
D: 40, 1
D: 41, 0
D: 42, 1
D: 43, 0
D: 44, 1
D: 45, 0
D: 46, 24
D: 47, 0
D: 48, 24
D: 49, 0
D: 50, 24
D: 51, 0
D: 52, 24
D: 53, 0
L0: 4000, 160, 15joint encoder transferred
My question is why is D:1 there? My understanding of unions and structures is that because command type is uint8_t, then it should only occupy one data space, and therefore UpperLimits[0] should start on D:1, but it seems that command_type is acting as a uint16_t and posting another bit. Why is this so?
Note: you may see that the index goes up to count data[53] which should be out of bounds, but I need to read this and send it so as to be able to deconstruct the data at the other end.
There is almost certainly a padding byte between commandtype and UpperLimits; the 2-byte myint16_t data type is aligned on an even byte boundary.
struct {
uint8_t commandtype;
myint16_t UpperLimits[4];
...
If you could print the size of the anonymous structure and union, you're likely to find that it is at least 54 bytes (where you think it should be 53). One of the disadvantages of untagged structure types embedded as anonymous members of a union is that there is no easy way to print the size of the structure. Give the structure a tag (struct tag { uint8_t commandtype; ...) so that you can print its size out.
There isn't an easy fix for that using the current framework.
You need to tell the compiler how to align the elements in your union or struct. Simply add #pragma pack(push,1) before your definitions to instruct the compiler to align adjacent elements on one-byte boundaries, and then use #pragma pack(pop) to revert to the compiler's default alignment. For performance reasons, you would not want to use one-byte alignment for all structs/unions/classes, so it's a good idea to wrap your union definition in the pragma pair.
Example:
#pragma pack(push,1)
union
{
uint_8 first;
uint_8 second;
} two_bytes;
#pragma pack(pop)
assert(sizeof two_bytes == 2);
I need a regex to match a value in which each character can be a digit from 0 to 9 or a space. The value must contain exactly 11 digits.
For example, it should match values in the format '012 345 678 90' or '01234567890'.
Can anyone please help me on this?
For the sake of other Aussie developers out there who may find this in the future:
^(\d *?){11}$
Matches 11 digits with zero or more spaces after each digit.
Edit:
As #ElliottFrisch mentioned, ABNs also have a mathematical formula for proper validation. It would be very difficult (or impossible) to use regex to properly validate an ABN - although the above regex would at least match 11 digit numbers with spacing. If you're after actual validation, perhaps regex isn't the tool for you in this case.
Further reading:
https://abr.business.gov.au/Help/AbnFormat
Here's a PHP implementation:
http://www.clearwater.com.au/code
Code copied from the above page in case it becomes unavailable someday:
// ValidateABN
// Checks ABN for validity using the published
// ABN checksum algorithm.
//
// Returns: true if the ABN is valid, false otherwise.
// Source: http://www.clearwater.com.au/code
// Author: Guy Carpenter
// License: The author claims no rights to this code.
// Use it as you wish.
function ValidateABN($abn)
{
$weights = array(10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19);
// strip anything other than digits
$abn = preg_replace("/[^\d]/","",$abn);
// check length is 11 digits
if (strlen($abn)==11) {
// apply ato check method
$sum = 0;
foreach ($weights as $position=>$weight) {
$digit = $abn[$position] - ($position ? 0 : 1);
$sum += $weight * $digit;
}
return ($sum % 89)==0;
}
return false;
}
And a javascript one which I found here:
http://www.mathgen.ch/codes/abn.html
REF OLD DEAD LINK: http://www.ato.gov.au/businesses/content.asp?doc=/content/13187.htm&pc=001/003/021/002/001&mnu=610&mfp=001/003&st=&cy=1
Confirm an ABN
The following formula can be used to verify the ABN you are allocated or to verify the ABN issued to a business you deal with.
To verify an ABN:
Subtract 1 from the first (left) digit to give a new eleven digit number
Multiply each of the digits in this new number by its weighting factor
Sum the resulting 11 products.
Divide the total by 89, noting the remainder.
If the remainder is zero the number is valid.
Digit Position
1
2
3
4
5
6
7
8
9
10
11
Weight
10
1
3
5
7
9
11
13
15
17
19
Example, to check the validity of ABN 53 004 085 616
5
3
0
0
4
0
8
5
6
1
6
Subtract 1 from first (left) digit to give new number
4
3
0
0
4
0
8
5
6
1
6
Apply weighting factor
10
1
3
5
7
9
11
13
15
17
19
(4x10)+(3x1)+(0x3)+(0x5)+(4x7)+(0x9)+(8x11)+(5x13)+(6x15)+(1x17)+ (6x19)
40+3+0+0+28+0+88+65+90+17+114
445/89 = 5 remainder 0
The remainder is zero so the number is valid.
Here is a C# Validation:
public static bool ValidateABN(string abn)
{
bool isValid = false;
int[] weight = { 10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
int weightedSum = 0;
//ABN must not contain spaces, comma's or hypens
abn = StripNonDigitData(abn);
//ABN must be 11 digits long
if (!string.IsNullOrEmpty(abn) & Regex.IsMatch(abn, "^\\d{11}$"))
{
//Rules: 1,2,3
for (int i = 0; i <= weight.Length - 1; i++)
{
weightedSum += (int.Parse(abn[i].ToString()) - ((i == 0 ? 1 : 0))) * weight[i];
}
//Rules: 4,5
return ((weightedSum % 89) == 0);
}
return isValid;
}
public static string StripNonDigitData(string input)
{
StringBuilder output = new StringBuilder("");
foreach (char c in input)
{
if (char.IsDigit(c))
{
output.Append(c);
}
}
return output.ToString();
}
And a VB.Net Validation:
Public Shared Function ValidateABN(ByVal abn As String) As Boolean
Dim isValid As Boolean = False
Dim weight() As Integer = {10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19}
Dim weightedSum As Integer = 0
'ABN must not contain spaces, comma's or hypens
abn = StripNonDigitData(abn)
'ABN must be 11 digits long
If Not String.IsNullOrEmpty(abn) And Regex.IsMatch(abn, "^\d{11}$") Then
'Rules: 1,2,3
For i As Integer = 0 To weight.Length - 1
weightedSum += (Integer.Parse(abn(i).ToString()) - (IIf(i = 0, 1, 0))) * weight(i)
Next
'Rules: 4,5
Return ((weightedSum Mod 89) = 0)
End If
Return isValid
End Function
Public Shared Function StripNonDigitData(ByVal input As String) As String
Dim output As New StringBuilder("")
For Each c As Char In input
If Char.IsDigit(c) Then
output.Append(c)
End If
Next
Return output.ToString
End Function
// return false if not correct AU vat format
function ABNValidation (val) {
val = val.replace(/[^0-9]/g, '');
let weights = new Array(10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19);
if (val.length === 11) {
let sum = 0;
weights.forEach(function(weight, position) {
let digit = val[position] - (position ? 0 : 1);
sum += weight * digit;
});
return sum % 89 == 0;
}
return false;
}
Another JavaScript version:
/**
* validate ABN
* #param {string} abn
* #return {boolean} is ABN number valid
*
* 0. ABN must be 11 digits long
* 1. Subtract 1 from the first (left) digit to give a new eleven digit number
* 2. Multiply each of the digits in this new number by its weighting factor
* 3. Sum the resulting 11 products
* 4. Divide the total by 89, noting the remainder
* 5. If the remainder is zero the number is valid
*/
var validateABN = function(abn){
var isValid = true;
//remove all spaces
abn = abn.replace(/\s/g, '');
//0. ABN must be 11 digits long
isValid &= abn && /^\d{11}$/.test(abn);
if(isValid){
var weightedSum = 0;
var weight = [10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
//Rules: 1,2,3
for (var i = 0; i < weight.length; i++) {
weightedSum += (parseInt(abn[i]) - ((i === 0) ? 1 : 0)) * weight[i];
}
//Rules: 4,5
isValid &= ((weightedSum % 89) === 0);
}
return isValid;
};
//tests
console.log(validateABN('51824753556'));
console.log(validateABN('51 824 753 556'));
console.log(validateABN('51824744556'));
Have you read up on regexes? This is as straightforward as it gets.
^[0-9 ]+$
For those using AngularJS, I have written a directive to do ABN validation:
var app = angular.module("demoapp", ["input-abn-directive"]);
and
<input type="abn" name="inputAbn" ng-model="modelAbn">
https://github.com/jasadams/input-abn-directive
TESTED ABN Javascript implementation
These are WORKING ABNs:
33 051 775 556 should work
14 069 979 460 should work
24 302 976 253 should work
These are INVALID ABNs:
65 065 987 968 should fail
12 345 678 965 should fail
function checkABN(value) {
let weights = new Array(10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19);
let abn = value.replace(/\D/g, ''); // strip non numeric chars
if (abn.length != 11) {
return false;
}
let abnFirstDigit = parseInt(abn.charAt(0)) - 1; //subtract 1 from first digit
abn = abnFirstDigit + abn.substring(1); // replace first digit with the substracted value
let total = 0;
for (let i = 0; i < 11; i++)
total += weights[i] * abn.charAt(i);
if (total == 0 || total % 89 != 0) {
return false;
} else {
return true;
}
}
The one from http://www.mathgen.ch/codes/abn.html has issues,
it won't allow 14 069 979 460 (which should be valid)
JavaScript version:
function checkABN(str) {
if (!str || str.length !== 11) {
return false;
}
var weights = [10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19],
checksum = str.split('').map(Number).reduce(
function(total, digit, index) {
if (!index) {
digit--;
}
return total + (digit * weights[index]);
},
0
);
if (!checksum || checksum % 89 !== 0) {
return false;
}
return true;
}
Answer to the Question
A lot of answers will include the regex [0-9]{11} or similar, which is sufficient for most situations, but none of the answers take into account the fact that ABNs cannot start with a zero.
The simplest regex available for determining an ABN, that takes into account the correct number of digits, any number of spaces and the non-zero leading digit, is: ^\s*[1-9](\s*\d){10}\s*$.
Standard Format
The standard number format is the 2,3,3,3 digit grouping pattern, as the first two digits form the check digits and the other 9 is the actual identifier.
The regex for specifically checking this format with or without spaces is ^[1-9]\d(\s?\d{3}){3}$.
This format can be easily mimicked using the PHP number_format function.
number_format( '12123123123', 0, '', ' ' ) === '12 123 123 123';
Actual Validation
Any of the other answers relating to actual validation should be mostly valid, but not 100% unless there is an additional check to ensure the number does not start with a zero. Expanding upon the current top rated answer, one additional check just needs to be made.
if ( strlen( $abn ) === 11 && $abn[0] > 0 ) { // or $abn > 9999999999
// ...
}
SQL Server solution - in a single case statement
As described in other answers, a single regular expression is unlikely to be able to validate an ABN. The case statement below can be used in Microsoft SQL Server to validate an ABN. You might like to create a persisted computed column on your table that contains the ABN field. Per comments below, if you return integers instead of text descriptions, then you can use such a field for relatively straightforward comparisons:
1 = valid
0 = invalid (wrong length)
-1 = invalid (fails the pattern check)
allowing you to use expressions like:
where abnValid = 1 -- match all valid records
where abnValid < 1 -- match all invalid records
The logic below for validating ABNs is based on Jeremy Thompson's answer here. The statement below is verbose and inefficient - so that it fits a single case statement so that you can use it with a persisted computed column - meaning the performance hit will be on update, not on select. It assumes your abnColumn is character based - so add an explicit cast if you're using a numeric type. It ignores space characters in your source data and assumes the first number of an ABN will not be zero.
case
when len(ltrim(rtrim(replace(abnColumn,' ','')))) <> 11 then 'Wrong length' -- or perhaps 0
when
(
((try_cast(left(ltrim(rtrim(replace(abnColumn,' ',''))),1) as int)-1)*10) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),10),1) as int)*1) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),9),1) as int)*3) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),8),1) as int)*5) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),7),1) as int)*7) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),6),1) as int)*9) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),5),1) as int)*11) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),4),1) as int)*13) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),3),1) as int)*15) +
(try_cast(left(right(ltrim(rtrim(replace(abnColumn,' ',''))),2),1) as int)*17) +
(try_cast(right(ltrim(rtrim(replace(abnColumn,' ',''))),1) as int)*19)
) %89 <> 0 then 'Check pattern fail' -- or perhaps -1
else 'Valid' -- or perhaps 1
end as abnValidationCheck -- or perhaps abnValid
For those TypeScript with reactive forms and angular2+ out there out there:
this.abnForm = new FormGroup({
abn: new FormControl('', [
this.abnValidator(),
Validators.pattern('^(\d *?){11}$')])
});
abnValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const weights = [10,1,3,5,7,9,11,13,15,17,19];
const cleanedABN = control.value.replace(/\D/g, '');
let valid = false;
if (cleanedABN.length === 11) {
let sum = 0;
weights.forEach((weight, ind) => {
const digit = parseInt(cleanedABN[ind], 10) - (ind === 0 ? 1 : 0);
sum += weight * digit;
});
valid = sum % 89 === 0;
} else {
valid = false;
}
return valid ? null : { invalid: true };
};
}
I am trying to find a way to import stat data into a game in progress Via spread sheets? Here's what I am working with:
Right now for example.. The spells, in order to name them, set stats, ect and be able to call them via Number I Have something like this going on in the actual code:
void spell(int & eMoney, int eSpell[10])
{
using namespace std;
char spellname[10][25] = {"Minor Heal", "Fire Shard", "Lightening Shard", "Ice Shard", "Magic Barrier", "Essence Of Life",
"Earth Shard", "Wind Shard", "Insigma", "Weaken"};
int spellcost[10] = {50, 80, 80, 80, 100, 100, 80, 80, 120, 80};
Which is all fine and dandy, it works... But it's an issue now and later.. I want to be able to use a spread sheet, like a CSV file, so I can have a spread sheet for like just spells, just swords, just clubs... I plan to have a very large selection, it's more ideal to be able to edit a single file in columns and rows and have the actual game pull the information from an external file when it's needed... But I am not able to figure out how to go about this? I am open to any ideas..
Here is an example of how I call on a spell's info now:
case 2:
do
{
cout << "Which spell would you like to cast?\n\n";
for(x=0;x<10;x++)
cout << x+1 << ". " << spellname[x] << ": " << eSpell[x] << " left" << endl;
cout << "11. Leave\n\n>> ";
cin >> decision;
system("cls");
}
while((decision<1)&&(decision>11)||(eSpell[decision-1]==0));
switch(decision)
and here is an example of the spread sheet I have in mind basically? Starting at A1:
Type sName mDmg sPrice
Spell 1 Minor Heal 10 100
Spell 2 Fire Shard 12 100
Spell 3 Lightening Shard 12 200
Spell 4 Ice Shard 12 150
Spell 5 Magic Barrier 10 130
Spell 6 Essence Of Life 15 10
Spell 7 Earth Shard 12 120
Spell 8 Wind Shard 12 230
Spell 9 Insigma 12 90
Spell 10 Weaken 12 100
Another Example:
Current Code:
char monsters[16][25] = {"Wolf", "Bear", "Bandit", "Traveler", "Gargoyle", "Knight", "Warlock", "Mammoth", "Cyclops", "Unicorn", "Dragon", "Your Mother", "Demon", "Jesus", "Satan", "God"};
//monster strengths
int monsterdamagemax[16] = {32, 42, 53, 53, 65, 65, 75, 75, 85, 85, 90, 90, 95, 95, 110, 110};
int monsterdamagemin[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int monsterdefensemax[16] = {2, 7, 13, 13, 20, 20, 25, 25, 35, 35, 40, 40, 45, 45, 55, 55};
int monsterdefensemin[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int monsterhealth[16] = {32, 52, 73, 73, 95, 95, 118, 118, 142, 142, 167, 167, 193, 193, 220, 220};
int monsterspeed[16] = {7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15};
int monstergold[16] = {20, 30, 41, 41, 53, 53, 66, 66, 80, 80, 95, 95, 110, 110, 125, 125};
Ideally, I want to be able to get all that from a CSV file like:
mID mName mDmgMax mDmgMin mDefMax mDefMin mHp mSpeed mGold
1 Wolf 32 0 2 0 32 7 20
2 Bear 42 0 7 0 52 8 30
3 Bandit 53 0 13 0 73 9 41
4 Traveler 53 0 13 0 73 9 41
5 Gargoyle 65 0 20 0 95 10 53
6 Knight 65 0 20 0 95 10 53
7 Warlock 75 0 25 0 118 11 66
8 Mammoth 75 0 25 0 118 11 66
9 Cyclops 85 0 35 0 142 12 80
10 Unicorn 85 0 35 0 142 12 80
11 Dragon 90 0 40 0 167 13 95
12 Your Mother 90 0 40 0 167 13 95
13 Demon 95 0 45 0 193 14 110
14 Jesus 95 0 45 0 193 14 110
15 Statan 110 0 55 0 220 15 125
16 God 110 0 55 0 220 15 125
How about writing a small command based application that creates records for you, and in your "main" program that is game, you just have to read these records.
A sample structure -
struct monster
{
int mID;
char mName[25]; //from your code
int mDmgMax;
//and these as well mDmgMin mDefMax mDefMin mHp mSpeed mGold
};
in this "helper" program read each data item (like the mName) in a record one by one, and insert in this structure. Write the structure to monsters.dat file
std::ofstream fout;
fout.open("monsters.dat", std::ios::app | std::ios::binary);
fout.write( (char*) &monsterInstance, sizeof(monsterInstance) );
fout.close();
This will simply append records. (I have skipped error checking and reading data.)
For greater ease, this program should be able to show current monsters, add monster, delete monster (by entering mID).
Reading such records in your main program should be a easy task.
If you're going to have a lot of table-based data to keep around, you might look into using SQLite. It has some interesting costs and benefits.
On the down side (maybe), it's SQL. It can be a bit more complex and depending on your searching algorithm, could be slower. It also can't be edited by hand, you need something to open the database (there are free tools available).
On the up side, you get all the sorting and filtering power of a database (anything you'll need, like spell='fireball' AND damage < 5), and SQLite is fast (easily enough to store game data in, and very possibly faster than your own code). You can store all your data in a single file for easy deployment or modding, with unique tables for each type (weapons, spells, characters, etc), and no server involved (SQLite is a single DLL).
Relational databases excel at working with consistently-formed tables of data, which is exactly what you have in a game environment (each object type has a few fields, not much variation, maybe some blanks, with various data types). SQLite, despite being the smallest database, can handle thousands of rows with excellent time, so you won't have to worry about your game data becoming unwieldy (which happens very quickly with pure text table files, like NWN(2)'s 2DA format).
There is a learning curve to it, but you do gain some simplicity in the future (adding a new object type is a new table and queries, not a whole lot of code) and a very stable data format and load/save library. Depending on your needs, it may be worth a shot.
As pointed in question comments, you should go for <fstream> if you really want to deal with CSV files. Using that approach, getline should be enough for what you need.
This thread in C++.com and this question should point you some directions on how to handle CSV.
I use Boost to parse the CSV files I work with. Here's a simple example.
I agree with peachykeen though, SQLite may suit you better, but maybe this will help you get started.
#include <iostream>
#include <fstream>
#include <vector>
#include <boost/tokenizer.hpp>
#include <boost/token_functions.hpp>
typedef std::vector<std::string> csvLine;
typedef std::vector<csvLine> csvLines;
typedef boost::tokenizer<boost::escaped_list_separator<char> > csvTokenizer;
csvLines ReadCSVFile(const std::string& fileName)
{
csvLines retVec;
std::ifstream inFile(fileName.c_str());
if(inFile)
{
std::string fileLine;
while(std::getline(inFile, fileLine))
{
csvTokenizer lineTokens(fileLine);
retVec.push_back(csvLine(lineTokens.begin(), lineTokens.end()));
}
inFile.close();
}
return retVec;
}
int main(int argc, char** argv)
{
csvLines lines(ReadCSVFile(argv[1]));
for(csvLines::iterator lineIt = lines.begin(); lineIt != lines.end(); ++lineIt)
{
for(csvLine::iterator tokenIt = (*lineIt).begin(); tokenIt != (*lineIt).end(); ++tokenIt)
{
std::cout << *tokenIt << " ";
}
std::cout << std::endl;
}
return 0;
}