Is there a simple (possibly obfuscated) math expression for the number of days in a given month? - date

For use in cases where a standard library is not available. Assume that the month is given as an unsigned integer.
I'd be interested in seeing the shortest arithmetic expression that gives the correct answer, allowing or disallowing bitwise operators & masks but not lookup tables. Partial expressions can be saved into a variable for readability to showcase the idea used.

Here's an approach that uses only four simple arithmetic and bitwise ops and a 26-bit constant:
int days_in_month(unsigned m) {
// 121110 9 8 7 6 5 4 3 2 1 0
return 28 + ((0b11101110111110111011001100u >> m * 2u) & 0b11);
}
If you also want to handle leap year (no mention of it in the question), you can take a similar approach, at the cost of a few more operations and a 50-bit constant:
int days_in_month2(unsigned m, bool ly) {
return 28 + ((0b11101110111110111011011111101110111110111011001100u >> (m + 12*ly) * 2u) & 0b11);
}
If you are willing the pass the leap year in a different way, e.g., setting a bit like month | 16 to indicate leap year, it would be more efficient.
I assume you pass the month as 1 to 12, not 0 to 11.
Tests and generated asm can be seen on godbolt.

Variation om #BeeOnRope nice answer.
#include <stdbool.h>
int DaysPerMonth(int Month, bool IsLeapYear) {
assert(Month >= 1 && Month <= 12);
// 0b11101110111110111011001100u
// 3 B B E E C C
return (((0x3BBEECCu | (IsLeapYear << 2*2)) >> Month*2) & 3) + 28;
}
#include <stdio.h>
int main() {
for (int ly = 0; ly <= 1; ly++) {
for (int m = 1; m <= 12; m++) {
printf("(%2d %2d), ", m, DaysPerMonth(m,ly));
}
puts("");
}
return 0;
}

Brute force answer in pseudocode for readability:
monthlength(month,is_leapyear) :=
oddmonth = ( month + (month >= 8) ? 1 : 0) % 2 // Or (month ^ (month >> 3))&1
feb_days_offset = (month == 2) ? 2 - is_leapyear : 0
return 30 + oddmonth - feb_days_offset
Where month >= 8 can also be implemented with a bitshift since it's just the fourth bit in an unsigned representation, so that oddmonth is (first bit) xor (fourth bit), which can be consisely written as (month ^ (month >> 3))&1 . Similarly, subtracting the feb offset can be thought of as flipping the second bit on febuary, and flipping the first bit during leap year february.
single line with no intermediate variables:
monthlength(month,isleapyear) := 30 + ( month + (month >= 8 ? 1 : 0)) % 2 - (month==2 ? (2 - isleapyear) : 0)
Alternatively, one that uses exclusively bitwise arithmetic and shifts using the tricks discussed above:
monthlength(month,leapyear) := 30 ^ (month==2)<<1 ^ (month==2)&leapyear ^ (month^month>>3)&1

unsigned int m, leapyr, y ;
//m = month range is 1 to 12
//y = year range is 00 to 99
leapyr = ( ( y & 0x03 ) && 1 ); //0 means leap year and 1 means Non leap year
m = 30 + ( ( m & 1 ) ^ ( 1 && ( m & 8 ) ) ) - ( ( !( m & 13 ) ) ) - ( ( !( m & 13 ) ) & leapyr );
My answer is considering year. If you don't want to use assign leapyr variable 0 or 1 as you wish.

Related

In Raku, how does one calculate the sum of positive divisors from a prime factorization?

In Raku, given a list of pairs (2 => 3, 3 => 2, 5 => 1, 7 => 4) ( representing the prime factorization of n = 2 3 · 3 2 · 5 1 · 7 4 ), how does construct a Raku expression for σ(n) = ( 2 0 + 2 1 + 2 2 + 2 3 ) · ( 3 0 + 3 1 + 3 2 ) · ( 5 0 + 5 1 ) · ( 7 0 + 7 1 + 7 2 + 7 3 + 7 4 ) ?
sub MAIN()
{
my $pairList = (2 => 3, 3 => 2, 5 => 1, 7 => 4) ;
say '$pairList' ;
say $pairList ;
say $pairList.WHAT ;
# Goal:
# from $pairList,
# the product (1 + 2 + 4 + 8) * (1 + 3 + 9) * (1 + 5) * (1 + 7 + 49 + 343 + 2401)
# = sigma ( 2^3 * 3^2 * 5^1 * 7^4 )
} # end sub MAIN
Update 1
Based upon the answer of #raiph, the following program breaks the overall process into stages for the newcomer to Raku (such as me) …
sub MAIN()
{
my $pairList = (2 => 3, 3 => 2, 5 => 1, 7 => 4) ;
say '$pairList' ;
say $pairList ;
say $pairList.WHAT ;
# Goal:
# from $pairList,
# the product (1 + 2 + 4 + 8) * (1 + 3 + 9) * (1 + 5) * (1 + 7 + 49 + 343 + 2401)
# the product (15) * (13) * (6) * (2801)
# sigma ( 2^3 * 3^2 * 5^1 * 7^4 )
# 3277170
# Stage 1 : ((1 2 4 8) (1 3 9) (1 5) (1 7 49 343 2401))
my $stage1 = $pairList.map: { (.key ** (my $++)) xx (.value + 1) } ;
say '$stage1 : lists of powers' ;
say $stage1 ;
say $stage1.WHAT ;
# Stage 2 : ((1 + 2 + 4 + 8) (1 + 3 + 9) (1 + 5) (1 + 7 + 49 + 343 + 2401))
my $stage2 = $stage1.map: { sum $_ } ;
say '$stage2 : sum each list' ;
say $stage2 ;
say $stage2.WHAT ;
# Stage 3 : (1 + 2 + 4 + 8) * (1 + 3 + 9) * (1 + 5) * (1 + 7 + 49 + 343 + 2401)
my $stage3 = $stage2.reduce( &infix:<*> ) ;
say '$stage3 : product of list elements' ;
say $stage3 ;
say $stage3.WHAT ;
} # end sub MAIN
A related post appears on Mathematics Stack Exchange.
Update 2
My original motivation had been to calculate aliquot sum s(n) = σ(n) - n. I found that prime factorization of each n is not necessary and seems inefficient. Raku and C++ programs calculating s(n) for n = 0 … 10 6 follow …
Raku
sub MAIN()
{
constant $limit = 1_000_000 ;
my #s of Int = ( 1 xx ($limit + 1) ) ;
#s[0] = 0 ;
#s[1] = 0 ;
loop ( my $column = 2; $column <= ($limit + 1) div 2; $column++ )
{
loop ( my $row = (2 * $column); $row <= $limit; $row += $column )
{
#s[$row] += $column ;
} # end loop $row
} # end loop $column
say "s(", $limit, ") = ", #s[$limit] ; # s(1000000) = 1480437
} # end sub MAIN
C++
(Observed to execute significantly faster than Raku)
#include <iostream>
#include <vector>
using namespace std ;
int main ( void )
{
const int LIMIT = 1000000 ;
vector<int> s ( (LIMIT + 1), 1 ) ;
s[0] = 0 ;
s[1] = 0 ;
for ( int col = 2 ; col <= (LIMIT + 1) / 2 ; col++ )
for ( int row = (2 * col) ; row <= LIMIT ; row += col )
s[row] += col ;
cout << "s(" << LIMIT << ") = " << s[LIMIT] << endl ; // s(1000000) = 1480437
} // end function main
There'll be bazillions of ways. I've ignored algorithmic efficiency. The first thing I wrote:
say [*] (2 => 3, 3 => 2, 5 => 1, 7 => 4) .map: { sum .key ** my $++ xx .value + 1 }
displays:
3277170
Explanation
1 say
2 [*] # `[op]` is a reduction. `[*] 6, 8, 9` is `432`.
3 (2 => 3, 3 => 2, 5 => 1, 7 => 4)
4 .map:
5 {
6 sum
7 .key # `.key` of `2 => 3` is `2`.
8 **
9 my # `my` resets `$` for each call of enclosing `{...}`
10 $++ # `$++` integer increments from `0` per thunk evaluation.
11 xx # `L xx R` forms list from `L` thunk evaluated `R` times
12 .value + 1
13 }
It is unlikely that Raku is ever going to be faster than C++ for that kind of operation. It is still early in its life and there are lots of optimizations to be gained, but raw processing speed is not where it shines.
If you are trying to find the aliquot sum for all of the numbers in a continuous range then prime factorization is certainly less efficient than the method you arrived at. Sort of an inverse Sieve of Eratosthenes. There are a few things you could change to make it faster, though still probably much slower than C++
About twice as fast on my system:
constant $limit = 1_000_000;
my #s = 0,0;
#s.append: 1 xx $limit;
(2 .. $limit/2).race.map: -> $column {
loop ( my $row = (2 * $column); $row <= $limit; $row += $column ) {
#s[$row] += $column ;
}
}
say "s(", $limit, ") = ", #s[$limit] ; # s(1000000) = 1480437
Where the prime factorization method really shines is for finding arbitrary aliquot sums.
This produces an answer in fractions of a second when the inverse sieve would likely take hours. Using the Prime::Factor module: from the Raku ecosystem
use Prime::Factor;
say "s(", 2**97-1, ") = ", (2**97-1).&proper-divisors.sum;
# s(158456325028528675187087900671) = 13842607235828485645777841

Palindrome Number: what is wrong with my code?

I am writing code in c++ to detect if an input number is a Palindrome Number, which means its reverse is the same as the origin. I have problems computing the reverse int.
e.g.
121 returns true;
123 returns false;
12321 returns true;
10 returns false;
I input 123 and the sum should be 321. However, my code keeps returning 386. I stepped into the function with xcode. Still, I have no idea why reverse += (3 * 10) + 2 turns to be 35 or why the final reverse number to be 386.
int origin = x;
int reverse = 0;
while (x != 0) {
int digit = x % 10;
reverse += ((reverse * 10) + digit);
x /= 10;
}
why reverse += (3 * 10) + 2 turns to be 35
Because += adds what is on the right to the existing value of what’s on the left. (3 * 10) + 2 is 32, but reverse was already 3 and so you are adding your 32 to the existing 3, which is 35.
You don’t want to add to the value of reverse; you want to replace it.
Change
reverse += ((reverse * 10) + digit)
To
reverse = ((reverse * 10) + digit)

Compare dates in Lua

I have a variable with a date table that looks like this
* table:
[day]
* number: 15
[year]
* number: 2015
[month]
* number: 2
How do I get the days between the current date and the date above? Many thanks!
You can use os.time() to convert your table to seconds and get the current time and then use os.difftime() to compute the difference. see Lua Wiki for more details.
reference = os.time{day=15, year=2015, month=2}
daysfrom = os.difftime(os.time(), reference) / (24 * 60 * 60) -- seconds in a day
wholedays = math.floor(daysfrom)
print(wholedays) -- today it prints "1"
as #barnes53 pointed out could be off by one day for a few seconds so it's not ideal, but it may be good enough for your needs.
You can use the algorithms gathered here:
chrono-Compatible Low-Level Date Algorithms
The algorithms are shown using C++, but they can be easily implemented in Lua if you like, or you can implement them in C or C++ and then just provide Lua bindings.
The basic idea using these algorithms is to compute a day number for the two dates and then just subtract them to give you the number of days.
--[[
http://howardhinnant.github.io/date_algorithms.html
Returns number of days since civil 1970-01-01. Negative values indicate
days prior to 1970-01-01.
Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
m is in [1, 12]
d is in [1, last_day_of_month(y, m)]
y is "approximately" in
[numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
Exact range of validity is:
[civil_from_days(numeric_limits<Int>::min()),
civil_from_days(numeric_limits<Int>::max()-719468)]
]]
function days_from_civil(y, m, d)
if m <= 2 then
y = y - 1
m = m + 9
else
m = m - 3
end
local era = math.floor(y/400)
local yoe = y - era * 400 -- [0, 399]
local doy = math.modf((153*m + 2)/5) + d-1 -- [0, 365]
local doe = yoe * 365 + math.modf(yoe/4) - math.modf(yoe/100) + doy -- [0, 146096]
return era * 146097 + doe - 719468
end
local reference_date = {year=2001, month = 1, day = 1}
local date = os.date("*t")
local reference_days = days_from_civil(reference_date.year, reference_date.month, reference_date.day)
local days = days_from_civil(date.year, date.month, date.day)
print(string.format("Today is %d days into the 21st century.",days-reference_days))
os.time (under Windows, at least) is limited to years from 1970 and up. If, for example, you need a general solution to also find ages in days for people born before 1970, this won't work. You can use a julian date conversion and subtract between the two numbers (today and your target date).
A sample julian date function that will work for practically any date AD is given below (Lua v5.3 because of // but you could adapt to earlier versions):
local
function div(n,d)
local a, b = 1, 1
if n < 0 then a = -1 end
if d < 0 then b = -1 end
return a * b * (math.abs(n) // math.abs(d))
end
--------------------------------------------------------------------------------
-- Convert a YYMMDD date to Julian since 1/1/1900 (negative answer possible)
--------------------------------------------------------------------------------
function julian(year, month, day)
local temp
if (year < 0) or (month < 1) or (month > 12)
or (day < 1) or (day > 31) then
return
end
temp = div(month - 14, 12)
return (
day - 32075 +
div(1461 * (year + 4800 + temp), 4) +
div(367 * (month - 2 - temp * 12), 12) -
div(3 * div(year + 4900 + temp, 100), 4)
) - 2415021
end

simple number series

This is a simple number series question, I have numbers in series like
2,4,8,16,32,64,128,256 these numbers are formed by 2,2(square),2(cube) and so on.
Now if I add 2+4+8 = 14. 14 will get only by the addition 2,4 and 8.
so i have 14in my hand now, By some logic i need to get the values which are helped to get 14
Example:
2+4+8 = 14
14(some logic) = 2,4,8.
This is an easy one:
2+4+8=14 ... 14+2=16
2+4+8+16=30 ... 30+2=32
2+4+8+16+32=62 ... 62+2=64
So you just need to add 2 to your sum, then calculate ld (binary logarithm), and then subtract 1. This gives you the number of elements of your sequence you need to add up.
e.g. in PHP:
$target=14;
$count=log($target+2)/log(2)-1;
echo $count;
gives 3, so you have to add the first 3 elements of your sequence to get 14.
Check the following C# code:
x = 14; // In your case
indices = new List<int>();
for (var i = 31; i >= i; i--)
{
var pow = Math.Pow(2, i);
if x - pow >= 0)
{
indices.Add(pow);
x -= pow;
}
}
indices.Reverse();
assuming C:
unsigned int a = 14;
while( a>>=1)
{
printf("%d ", a+1);
}
if this is programming, something like this would suffice:
int myval = 14;
int maxval = 256;
string elements = "";
for (int i = 1; i <= maxval; i*=2)
{
if ((myval & i) != 0)
elements += "," + i.ToString();
}
Use congruency module 2-powers: 14 mod 2 = 0, 14 mod 4 = 2, 14 mod 8 = 6, 14 mod 16 = 14, 14 mod 32 = 14...
The differences of this sequence are the numbers you look for 2 - 0 = 2, 6 - 2 = 4, 14 - 6 = 8, 14 - 14 = 0, ...
It's called the p-adic representation and is formally a bit more difficult to explain, but I hope this gives you an idea for an algorithm.

"Nearly divisible"

I want to check if a floating point value is "nearly" a multiple of 32. E.g. 64.1 is "nearly" divisible by 32, and so is 63.9.
Right now I'm doing this:
#define NEARLY_DIVISIBLE 0.1f
float offset = fmodf( val, 32.0f ) ;
if( offset < NEARLY_DIVISIBLE )
{
// its near from above
}
// if it was 63.9, then the remainder would be large, so add some then and check again
else if( fmodf( val + 2*NEARLY_DIVISIBLE, 32.0f ) < NEARLY_DIVISIBLE )
{
// its near from below
}
Got a better way to do this?
well, you could cut out the second fmodf by just subtracting 32 one more time to get the mod from below.
if( offset < NEARLY_DIVISIBLE )
{
// it's near from above
}
else if( offset-32.0f>-1*NEARLY_DIVISIBLE)
{
// it's near from below
}
In a standard-compliant C implementation, one would use the remainder function instead of fmod:
#define NEARLY_DIVISIBLE 0.1f
float offset = remainderf(val, 32.0f);
if (fabsf(offset) < NEARLY_DIVISIBLE) {
// Stuff
}
If one is on a non-compliant platform (MSVC++, for example), then remainder isn't available, sadly. I think that fastmultiplication's answer is quite reasonable in that case.
You mention that you have to test near-divisibility with 32. The following theory ought to hold true for near-divisibility testing against powers of two:
#define THRESHOLD 0.11
int nearly_divisible(float f) {
// printf(" %f\n", (a - (float)((long) a)));
register long l1, l2;
l1 = (long) (f + THRESHOLD);
l2 = (long) f;
return !(l1 & 31) && (l2 & 31 ? 1 : f - (float) l2 <= THRESHOLD);
}
What we're doing is coercing the float, and float + THRESHOLD to long.
f (long) f (long) (f + THRESHOLD)
63.9 63 64
64 64 64
64.1 64 64
Now we test if (long) f is divisible with 32. Just check the lower five bits, if they are all set to zero, the number is divisible by 32. This leads to a series of false positives: 64.2 to 64.8, when converted to long, are also 64, and would pass the first test. So, we check if the difference between their truncated form and f is less than or equal to THRESHOLD.
This, too, has a problem: f - (float) l2 <= THRESHOLD would hold true for 64 and 64.1, but not for 63.9. So, we add an exception for numbers less than 64 (which, when incremented by THRESHOLD and subsequently coerced to long -- note that the test under discussion has to be inclusive with the first test -- is divisible by 32), by specifying that the lower 5 bits are not zero. This will hold true for 63 (1000000 - 1 == 1 11111).
A combination of these three tests would indicate whether the number is divisible by 32 or not. I hope this is clear, please forgive my weird English.
I just tested the extensibility to other powers of three -- the following program prints numbers between 383.5 and 388.4 that are divisible by 128.
#include <stdio.h>
#define THRESHOLD 0.11
int main(void) {
int nearly_divisible(float);
int i;
float f = 383.5;
for (i=0; i<50; i++) {
printf("%6.1f %s\n", f, (nearly_divisible(f) ? "true" : "false"));
f += 0.1;
}
return 0;
}
int nearly_divisible(float f) {
// printf(" %f\n", (a - (float)((long) a)));
register long l1, l2;
l1 = (long) (f + THRESHOLD);
l2 = (long) f;
return !(l1 & 127) && (l2 & 127 ? 1 : f - (float) l2 <= THRESHOLD);
}
Seems to work well so far!
I think it's right:
bool nearlyDivisible(float num,float div){
float f = num % div;
if(f>div/2.0f){
f=f-div;
}
f=f>0?f:0.0f-f;
return f<0.1f;
}
For what I gather you want to detect if a number is nearly divisible by other, right?
I'd do something like this:
#define NEARLY_DIVISIBLE 0.1f
bool IsNearlyDivisible(float n1, float n2)
{
float remainder = (fmodf(n1, n2) / n2);
remainder = remainder < 0f ? -remainder : remainder;
remainder = remainder > 0.5f ? 1 - remainder : remainder;
return (remainder <= NEARLY_DIVISIBLE);
}
Why wouldn't you just divide by 32, then round and take the difference between the rounded number and the actual result?
Something like (forgive the untested/pseudo code, no time to lookup):
#define NEARLY_DIVISIBLE 0.1f
float result = val / 32.0f;
float nearest_int = nearbyintf(result);
float difference = abs(result - nearest_int);
if( difference < NEARLY_DIVISIBLE )
{
// It's nearly divisible
}
If you still wanted to do checks from above and below, you could remove the abs, and check to see if the difference is >0 or <0.
This is without uing the fmodf twice.
int main(void)
{
#define NEARLY_DIVISIBLE 0.1f
#define DIVISOR 32.0f
#define ARRAY_SIZE 4
double test_var1[ARRAY_SIZE] = {63.9,64.1,65,63.8};
int i = 54;
double rest;
for(i=0;i<ARRAY_SIZE;i++)
{
rest = fmod(test_var1[i] ,DIVISOR);
if(rest < NEARLY_DIVISIBLE)
{
printf("Number %f max %f larger than a factor of the divisor:%f\n",test_var1[i],NEARLY_DIVISIBLE,DIVISOR);
}
else if( -(rest-DIVISOR) < NEARLY_DIVISIBLE)
{
printf("Number %f max %f less than a factor of the divisor:%f\n",test_var1[i],NEARLY_DIVISIBLE,DIVISOR);
}
}
return 0;
}