Java long is calculated wrongly - android

Consider this piece of code:
// calculate age of dog
long interval = 1000*60*60*24*30;
int ageInWeeks = Weeks.weeksBetween(geburtsDatumDateTime, nowDateTime).getWeeks();
if (ageInWeeks < 20){
// wöchentlich
interval = 1000*60*60*24*7;
} else if (ageInWeeks >= 20 && ageInWeeks < 52){
// 2-wöchentlich
interval = 1000*60*60*24*14;
} else if (ageInWeeks >= 52){
// monatlich
interval = 1000*60*60*24*30;
}
The debugger shows, that in case of ageInWeeks >= 52 the interval is: -1702967296, but it should be: 2592000000
The minus sign suggests some kind of overflow error.
However the maximum value of a long in Java is 2E63-1 which is: 9.2233E18
What I am missing here? Is an Android maximum value for a long smaller?

You're computing 32-bit signed ints, the computation overflows, and then you assign the result to a long.
Do your calculation in 64 bits by making one of the operands a long. For example, add L to one of the operands to make it a long literal:
interval = 1000L*60*60*24*30;

As laalto said, adding a 'L' should make it work.
However, for avoiding these kind of errors in the future, you could use the TimeUnit class (available in Android SDK):
long interval = TimeUnit.DAYS.toMillis(30);

Related

Calculate earlier and later times, then compare with a given time

I need to calculate if a certain time is between 30 minutes earlier and 20 minutes later than the current time.
Any idea how to do this?
The problem is when the time is 23:50h, for example. So I can't do a simple comparison since 23 is greater than 00. But I must consider it smaller since it's another day.
Example:
Now is 23:45. Testing 23:50.
23:45 - 30 minutes = 23:15.
23:45 + 20 minutes = 00:05.
Is 23:50 between 23:15 and 00:05?
Another example:
Now is 00:05. Testing 00:15.
00:05 - 30 minutes = 23:35.
00:05 + 20 minutes = 00:25.
Is 00:15 between 23:35 and 00:25?
--
minSdkVersion is 22, and this further limits the available solutions.
The easiest way to go is :
Compare Hours separately from minutes.
Or also you can take the Hours, multiply them for 60 and then add the returning value to the minutes amount, that will end up with a "only minute" calculation between the 2 times. You can make whatever operation you need.
The only case you should calculate is that one you are in a different day, but that dipends and what you are trying to accomplish!
CODE IN JAVA (OLD VERSION):
public class Main
{
public static void main(String[] args)
{
//Input TIME
String date = "23.45";
//Calculating the TIME in MINUTES ONLY
int date_m = normalizeTime(date);
//CALCULATE MAX AND MIN TIMES
int max = date_m+20;
int min = date_m-30;
/*
Working like that we don't
need to worry about the day Before or After
*/
//JUST DEBUG PRINTS TO SHOW YOU THAT
System.out.println("MAX TIME : "+max);
System.out.println("MIN TIME : "+min);
//The TIME that has to be tested
String testDate = "23.50";
//Calculating the TIME in MINUTES ONLY
int testDate_m = normalizeTime(testDate);
//JUST A DEBUG PRINT TO SHOW YOU THE TESTED TIME
System.out.println("TESTED TIME : "+testDate_m);
/*
If the testDate_m is Between the MAX and MIN values it's
TRUE else it's FALSE
If needed you can adjust with >= or <=
That doesn't matter for the logic.
*/
if(testDate_m<max && testDate_m>min)
System.out.println("IT IS BETWEEN!");
else
System.out.println("IT ISN'T BETWEEN!");
//DONE!
}
/*
Just a Method to clean up the code:
Basically it will Split the string in HOURS and MINUTES
and it will make a simple operation of : Hour*60(Transforming it to minutes) + minutes
The return is an INT that represent the inserted TIME as a MINUTE ONLY TIME.
If the returned number is more than 24*60 it's the Day Next (don't need to worry about that)
If the returned number is less than 0 it's the Previous Day (don't need to worry about that)
*/
private static int normalizeTime(String time)
{
int h = Integer.parseInt(time.substring(0,2));
int m = Integer.parseInt(time.substring(3,5));
return h*60+m;
}
}
CODE IN JAVA (NEW VERSION) :
public class Main
{
public static void main(String[] args)
{
boolean inTime = true;
//Input TIME
String date = "23.50";
//Calculating the TIME in MINUTES ONLY
int date_m = normalizeTime(date);
//CALCULATE MAX AND MIN TIMES
int max = date_m+20;
int min = date_m-30;
int prevMin = max;
int nextMax = min;
if(min<0)
{
prevMin = 24*60+min;
nextMax = 24*60+max;
}
else if(max>24*60)
{
prevMin = min-24*60;
nextMax = max-24*60;
}
/*
Working like that we don't
need to worry about the day Before or After
*/
//JUST DEBUG PRINTS TO SHOW YOU THAT
System.out.println("Between :"+min+" and "+max);
System.out.println("OR");
System.out.println("Between : "+prevMin+" and "+nextMax);
//The TIME that has to be tested
String testDate = "00.05";
//Calculating the TIME in MINUTES ONLY
int testDate_m = normalizeTime(testDate);
//JUST A DEBUG PRINT TO SHOW YOU THE TESTED TIME
System.out.println("TESTED TIME : "+testDate_m);
/*
If the testDate_m is Between the MAX and MIN values it's
TRUE else it's FALSE
If needed you can adjust with >= or <=
That doesn't matter for the logic.
*/
if((testDate_m<max && testDate_m>min) || (testDate_m<nextMax && testDate_m>prevMin))
System.out.println("IT IS BETWEEN!");
else
System.out.println("IT ISN'T BETWEEN!");
//DONE!
}
/*
Just a Method to clean up the code:
Basically it will Split the string in HOURS and MINUTES
and it will make a simple operation of : Hour*60(Transforming it to minutes) + minutes
The return is an INT that represent the inserted TIME as a MINUTE ONLY TIME.
If the returned number is more than 24*60 it's the Day Next (don't need to worry about that)
If the returned number is less than 0 it's the Previous Day (don't need to worry about that)
*/
private static int normalizeTime(String time)
{
int h = Integer.parseInt(time.substring(0,2));
int m = Integer.parseInt(time.substring(3,5));
return h*60+m;
}
}
The easiest way is just to work with timestamps.
long time = new Date().getTime();
long thiry_earlier = time - minutes_to_ms(30);
long twenty_later = time + minutes_to_ms(20);
if(compare < twenty_later && compare > thirty_earlier) {
//do whatever
}
long minutes_to_ms(long minutes) {
return minutes*60*1000;
}
There's some nicer conversion functions you can use nowdays I'm just too lazy to look them up. But working with raw timestamps makes everything easier for comparisons.

Get 64bit timestamps from a 32bit timer

On my stm32wb55, I am using the 32bit-timer "tim2" for reading the time from 32bit-register "CNT" since system startup. With prescaling, I display the time in microseconds on my putty-console and it works very well. But now, I need to memory higher values. So I want to memory the time in a 64bit integer.
Does anyone know a simple way for doing that?
The tim2 timer is a 32bit resolution timer, you want a 64bit resolution. There are two ways to emulate a 64bit counter, to keep track of your uptime.
One would be incrementing a variable each time you reach the unit of time that you want to keep track of. But that would be extremely inefficient giving that the microcontroller would be doing a lot of constant context switching.
The second way would be to extend the timer with a 32bit variable. Then incrementing such variable on an overflow.
MSB LSB
+--------------+ +--------------+
| 32bit uint | | 32bit timer |
+--------------+ +--------------+
The way this works is that after the timer reaches 0xffffffff which is the maximum for a 32bit unsigned counter, the timer will overflow and start back at 0. If there was another bit after that 32'th bit, it will flip on(which is the same as incrementing). What you can do is emulate this exact behavior by incrementing a variable.
First, set up your timer.
static TIM_HandleTypeDef s_TimerInstance = {
.Instance = TIM2
};
void setup_timer()
{
__TIM2_CLK_ENABLE();
s_TimerInstance.Init.Prescaler = ##; //Chose the correct value that fits your needs
s_TimerInstance.Init.CounterMode = TIM_COUNTERMODE_UP;
s_TimerInstance.Init.Period = 0xffffffff; //Chose the correct value that fits your needs
s_TimerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //Also choose this value
s_TimerInstance.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&s_TimerInstance);
HAL_TIM_Base_Start(&s_TimerInstance);
}
Your handler, this has to be called each time your timer reaches 0xffffffff
extern void TIM2_IRQHandler();
void TIM2_IRQHandler()
{
HAL_TIM_IRQHandler(&s_TimerInstance);
}
uint32_t extension;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
extension++; //Increment
}
Combine the extension variable and the timer value. Use this function each time you want to get the extender counter value. You can make it inline to avoid extra calls, or as a macro.
uint64_t get_time()
{
return (extension << 32) & (__HAL_TIM_GET_COUNTER(&s_TimerInstance));
}
Now glue everything together
int main(void)
{
HAL_Init(); //Initialize HAL library
InitializeTimer(); //Initialize timer
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
while(1);
}
Note, that now tim2 will be used until it overflows. It should not be changed, or the following code will not work. Also, setup the divider, so the timer increment each microsecond as you stated earlier.
Also, you can use the timer to count seconds and then calculate the microsecond instead. If you count seconds instead you can count up to 2^32 seconds which is 4294967296. A year has about 31536000 seconds. With a 32bit counter (4294967296/31536000) you can count up to 136.19252 years of uptime. Then get the microseconds by dividing the uptime with 1000000 (uptime/1000000). I don't know what are you planning to do with the microcontroller, but counting seconds sounds more sensical for me.
If you really want precision, you can still do it by counting seconds, you can add the timer counter value to the microsecond count, which you can get by diving the seconds down into microseconds, that way you offset microseconds that haven't been added to the second count.
If you only access this from a non-ISR [non interrupt service] context, it's pretty simple.
If you have an ISR, the base level needs to lock/unlock interrupt handling. The ISR does not have to be related to the timer interrrupt. It could be for any ISR (e.g. tty, disk, SPI, video/audio, whatever).
Here's some representative code for a simple semi-baremetal implementation [this is similar to what I've done in some R/T commercial products, notably in a microblaze inside a Xilinx FPGA]:
typedef unsigned int u32;
typedef unsigned long long u64;
volatile int in_isr; // 1=inside an ISR
volatile u32 oldlo; // old LSW timer value
volatile u32 oldhi; // MSW of 64 bit timer
// clear and enable the CPU interrupt flag
void cli(void);
void sti(void);
// tmr32 -- get 32 bit timer/counter
u32 tmr32(void);
// tmrget -- get 64 bit timer value
u64
tmrget(void)
{
u32 curlo;
u32 curhi;
u64 tmr64;
// base level must prevent interrupts from occurring ...
if (! in_isr)
cli();
// get the 32 bit counter/timer value
curlo = tmr32();
// get the upper 32 bits of the 64 bit counter/timer
curhi = oldhi;
// detect rollover
if (curlo < oldlo)
curhi += 1;
oldhi = curhi;
oldlo = curlo;
// reenable interrupts
if (! in_isr)
sti();
tmr64 = curhi;
tmr64 <<= 32;
tmr64 |= curlo;
return tmr64;
}
// isr -- interrupt service routine
void
isr(void)
{
// say we're in an ISR ...
in_isr += 1;
u64 tmr = tmrget();
// do stuff ...
// leaving the ISR ...
in_isr -= 1;
}
// baselevel -- normal non-interrupt context
void
baselevel(void)
{
while (1) {
u64 tmr = tmrget();
// do stuff ...
}
}
This works fine if tmrget is called frequently enough that it catches each rollover of the 32 bit timer value.

Converting string with time to minutes

I am working on an Android app that gets a time (duration) value as string.
For example, the app can get a value like: 6 hours 43 mins
or a value like: 15 mins
I am looking for a way to convert this strings to an integer value in minutes.
I have tried using this function, but I can´t extract the needed values:
str = str.replaceAll("[^\\d.]", "");
Edit:
it could be possible a result like 6 hours, the only known condition is that minutes are always rounded to an integer, the minimum value is 1 min
Using a Regex to get each couple numeric/time_unit. You can easily parse that with :
(\\d+) (\\w+)
Group 1 : numeric value
Group 2 : time unit
(note that I used a space between the two (could be optional if you want)
Using Java Pattern class to use that regex
Pattern p = Pattern.compile("(\\d+) (\\w+)");
Then you just have to iterate on each match to get the couple type/value
Matcher m = p.matcher(s);
while(m.find()){
String type = m.group(2);
int value = Integer.parseInt(m.group(1))
...
}
From that, just use a switch to convert the number into minute and add it to the variable, omitting the break to have a nice (but not efficient) converter :
switch(type){
//Add more time unit in the correct order if needed
case "days":
value *= 24;
case "hours":
value *= 60;
case "mins":
mins += value;
break;
}
Each type will convert the value into a correct number of minute, at the end, you will have the result in minutes.
Problem: There are few concerns as you never know without putting extra conditions like:
15 hours and 15 mins both will be stored in same integer value , you eventually need to differentiate them on some conditions to cater all the issues.
Coming to the question, you may achieve all this by using String split cases but you need to manually cater all the cases keeping in mind a user can use any spell words like hours can be hrs and so on
You could split the String at the whitespace and use the values in the array.
String value1 = "6 hours 43 mins";
String value2 = "15 mins";
String[] resultList1 = value1.split(" ");
String[] resultList2 = value2.split(" ");
int minutes1 = 0;
int minutes2 = 0;
if(resultList1.length == 4) {
minutes1 = Integer.parseInt(resultList1[0]) * 60 + Integer.parseInt(resultList1[2]);
} else {
minutes1 = Integer.parseInt(resultList1[0]);
}
if(resultList2.length == 4) {
minutes2 = Integer.parseInt(resultList2[0]) * 60 + Integer.parseInt(resultList2[2]);
} else {
minutes2 = Integer.parseInt(resultList2[0]);
}
System.out.println(minutes1);
System.out.println(minutes2);
The result is:
403
15
Either String split() or Pattern Matcher, as earlier answers suggest, will work. I'm not sure which will be more efficient though, but it's probably irrelevant in this case. My version:
String timeStr = "2 hours 15 mins";
String[] parts = timeStr.split(" ");
int totalMins = 0;
for(int i=1; i< parts.length; i+=2) {
// Add checking for "days", etc., if necessary.
if(parts[i].equals("hours")) {
int h = Integer.parseInt(parts[i-1]);
totalMins += 60 * h;
} else if(parts[i].equals("mins")) {
int m = Integer.parseInt(parts[i-1]);
totalMins += m;
}
}
System.out.println("totalMins = " + totalMins);
>> totalMins = 135
If you can get each minute and hours separately you can use string.replace("mins", "") then use Integer.parseInt().
If you get overral like 6 hours 43 mins you must split the string.
I am not sure whether this can be done in a single regex, but if I were you I would use a different regex to find the number of hours, the number of minutes, the number of seconds, etc.
Given a string in the format you mentioned, you can first extract the number of hours by using this regex:
\d+(?= hours?)
Then extract the number of minutes:
\d+(?= mins?)
If seconds can appear in the input string, you can use this to extract seconds as well:
\d+(?= secs?)
If any of the regexes don't match, that means there isn't that information in the string.
String time = "6 hours 43 mins";//or (43 mins) or (6 hours)
int h, m;
String[] parts = time.split(" ");
if (parts.length == 4) {
h = parts[1];
m = parts[3];
} else if (parts.length == 2) {
if (parts[1].isEqualTo("hours") {
h = parts[0];
} else if (parts[1].isEqualTo("mins") {
m = parts[0];
}
}
return h*60+m;

ArrayList.add() causing OutOfMemory error?

For the first time today, I've met an OutOfMemory Error. I'm trying to calculate moving averages out of some data into an ArrayList, and had a crash at the first .add() step. The method is shown below
public ArrayList<Long> getNdaySMA(List<HistoricalQuote> history, int range){
long sum =0;
long SMA = 0;
ArrayList<Long> SMAs = new ArrayList<Long>();
//realRange is made due to the differences in defining "range in calculation vs speech
//a 10 day range for day 9 is actually from prices of day0 to day9, inclusive
int realRange =range-1;
//First step, add in placeholder 0s for the days within the range that have no value
//so if 10 day range, we have 0-> 9
for (int i=0;i<i+realRange;i++){
SMAs.add(i,0L);
}
//Next, actually calculate the SMAs for i.e. day 10
for (int i =0;i<history.size();i++){
//should be k<10, 0......9 = 10 days
for(int k=i+realRange;k==i;k--){
//Sum first from k=i+range-1 , go down to i.
//This should give us a value of RANGE
sum +=history.get(k).getClose().longValue();
}
//after summing up, we add calculate SMA and add it to list of SMAs
SMA = sum/range;
//we add the corresponding SMA to index i+range, made up of values calculated from before it
//to excel
SMAs.add(i+realRange,SMA);
sum =0;
}
return SMAs;
}
The stacktrace is as follows
java.lang.OutOfMemoryError
at java.util.ArrayList.add(ArrayList.java:154)
at com.xu.investo.MethodDatabase.getNdaySMA(MethodDatabase.java:46)
Where Line 46 refers to
SMAs.add(i,0L);
Is this error occuring due to the use of the Long number format? Any suggestions are welcome.
looks like infinite loop:
for (int i=0;i<i+realRange;i++)
i will always be less then i+realRange for realRange greater then zero:
I think I've identified the problem.
I may have created an infinite loop at this line
for (int i=0;i<i+realRange;i++){
SMAs.add(i,0L);
}

Android CPU usage of each function

Currently in my Android code what I am doing to calculate each function CPU Usage is -
double start = System.currentTimeMillis();
double start1 = Debug.threadCpuTimeNanos();
foo();
double end = System.currentTimeMillis();
double end1 = Debug.threadCpuTimeNanos();
double t = (end - start);
double t1 = (end1 - start1)/1000000;
double CPUusage;
if(t==0){
CPUusage = 0;
}else{
CPUusage = (t1/t) * 100;
}
I am doing t1/t to calculate CPU Usage. Is this a correct way of calculating CPU usage of each function in my Android code or is it conceptually wrong? Request someone to guide me in this.
From documentation:
static long currentTimeMillis()
Returns the current time in milliseconds since January 1, 1970 00:00:00.0 UTC.
Please, replace the double(s) you are using, with long(s).
While long(s) have precision issues, they are almost irrelevant for the variables used, also, the rounding will likely be close enough, that the returned value can be used in relation with each other
Also, you are comparing two independent values. Try either the current thread, or the full thread time.
From the Debug documentation:
public static long threadCpuTimeNanos()
Added in API level 1
Get an indication of thread CPU usage. The value returned indicates the amount of time that the current thread has spent executing code or waiting for certain types of I/O. The time is expressed in nanoseconds, and is only meaningful when compared to the result from an earlier call. Note that nanosecond resolution does not imply nanosecond accuracy. On system which don't support this operation, the call returns -1.
Try using, in the same Runnable (sequentially placed method calls):
long start = Debug.threadCpuTimeNanos();
foo();
long finish = Debug.threadCpuTimeNanos();
long outputValue = finish - start ;
System.out.println("foo() took " + outputValue + " ns.");

Categories

Resources