Java function to calculate difference in charge? - java

This object has a max charge of 1000. And when you drain 100, and then drain 1000, the second drain is supposed to return 900. What function to use that will allow me to return 900 because that is that max amount that can be drained as you can't drain a negative number?
I tried,
public double drain(double minutes) {
double drain = cameraPowerConsumption * minutes;
batteryCharge = Math.max(batteryCharge - drain, 0);
totalDrain += drain;
return drain;
but it returns 1000 instead of 900, after already draining 100. I think the drain variable needs to be changed. Without conditionals if that matters.

The amount drained cannot be greater than the battery's remaining charge:
double drain = Math.min(batteryCharge, cameraPowerConsumption * minutes);
After making that adjustment to your code, the rest is simple:
double drain = Math.min(batteryCharge, cameraPowerConsumption * minutes);
batteryCharge -= drain;
totalDrain += drain;
return drain;

To keep the batteryCharge value when subtracting a larger value, you can use the ternary operator (source) representing if/else. If batteryCharge - drain is less than 0 then keep that value, otherwise save the substraction value. Instead use this:
batteryCharge = Math.max(batteryCharge - drain, 0);
Try this:
batteryCharge = batteryCharge - drain < 0 ? batteryCharge : batteryCharge - drain;

Just simple
public double drain(double minutes) {
double drain = cameraPowerConsumption * minutes;
if (drain > batteryCharge){
totalDrain +=batteryCharge;
return batteryCharge;
}
totalDrain +=drain;
return (batteryCharge - drain);
}

Related

Generate specific intervals between two time/date in Java

I want to generate intervals between two given date/time.
For instance, say for 24 hour format (HH:MM), I have these two endpoints, 00:00 and 11:51, and suppose I want to partition it in 24 pieces. So my calculation is like this:
(hour * 3600 + min * 60) / 24
If I use calendar.add(Calendar.SECOND, (hour * 3600 + min * 60) / 24), I am getting wrong dates/time. My calculation is double and I think calendar.add() does not support double. Like it is taking 28.883 as 29.
In essence I want something like this:
now : 15:57
today start : 00:00 (24hh)
output : 00:00, 00:47.85, …, 15:57
The actual problem with your code is that you are performing integer division. I assume both hour and min are defined as integer types. The formula (hour * 3600 + min * 60) / 24 always yields an integer type. If you change the code to (hour * 3600 + min * 60) / 24d the expression yields a floating point value at least.
The next problem is indeed that Calendar.add(int field, int amount) accepts only an integer as second argument. Of course, if you are passing Calendar.SECOND as first argument, then your precision is not higher than seconds. You can use Calendar.MILLISECOND to get a higher precision.
However, I suggest using the new Java Date and Time API, instead of the troublesome old API:
LocalTime startTime = LocalTime.of(0, 0);
LocalTime endTime = LocalTime.of(11, 51);
long span = Duration.between(startTime, endTime).toNanos();
final int n = 23; // Number of pieces
LongStream.rangeClosed(0, n)
.map(i -> i * span / n)
.mapToObj(i -> startTime.plusNanos(i))
.forEach(System.out::println);
You need to save your start date in a calendar object and then when you generate each division use the formula:
startCalendar.add(Calendar.Second, count * (hour * 3600 + min * 60) / 24))
That way the arithmetic errors that you get by dividing by 24 (or whatever) are not accumulated.
Here’s a variant of MC Emperor’s fine code. I wanted to leave the math to the library class. Duration has methods dividedBy and multipliedBy that we can use to our advantage.
LocalTime startTime = LocalTime.of(0, 0);
LocalTime endTime = LocalTime.of(11, 51);
final int n = 24; // Number of pieces
Duration piece = Duration.between(startTime, endTime).dividedBy(n);
LocalTime[] partitionTimes = IntStream.rangeClosed(0, n)
.mapToObj(i -> startTime.plus(piece.multipliedBy(i)))
.toArray(LocalTime[]::new);
System.out.println(Arrays.toString(partitionTimes));
Output:
[00:00, 00:29:37.500, 00:59:15, 01:28:52.500, 01:58:30, 02:28:07.500,
02:57:45, 03:27:22.500, 03:57, 04:26:37.500, 04:56:15, 05:25:52.500,
05:55:30, 06:25:07.500, 06:54:45, 07:24:22.500, 07:54, 08:23:37.500,
08:53:15, 09:22:52.500, 09:52:30, 10:22:07.500, 10:51:45,
11:21:22.500, 11:51]
Is there a rounding problem? With a start time in whole minutes and 24 pieces there won’t be since 24 divides evenly into the number of nanoseconds in a minute. With another number of pieces you may decide whether the slight inaccuracy is worth worrying about. If it is, for each partitioning time multiply before you divide.

How to multiply a double by a percentage

Hello I was just wondering How I could perform this operation in java?
What I have done is incorrect, I may be looking at this wrong!, some help would be appreciated.
double result = n / n * 100 <= 100;
First of all, there are two operations, the first one is a math operation, it is before to the '<='. The second one, is a boolean operation, so you should think what is the purpose of that inequality (show the boolean result or the math result).
On the other hand, if you want to store that result you should do this:
boolean result = n/n * 100 <= 100;
Because, it is an inequality.
Because you are comparing the value of n / n * 100 to 100, the result would be a boolean (true/false).
If you want to accomplish something with this, you would do something like this:
double result = (n / n) * 1; //Because 100% is = to 1
if(result <= 1){
//Do stuff
}
If you wanted to use a different percentage, then you would just replace 1 with the difference of 1 and that percentage. For example, if your percentage was 75%, then you would multiply by 0.75.

Math: when do we use logarithms and how does it work?

I were solving:
We know the content of the evaporator (content in ml), the percentage of foam or gas lost every day (evap_per_day) and the threshold (threshold) in percentage beyond which the evaporator is no longer useful. All numbers are strictly positive. The program reports the nth day (as an integer) on which the evaporator will be out of use.
My solution with recursion:
if (content > (initialContent / 100) * threshold) {
double postContent = content - (content / 100) * evap_per_day;
iterations++;
return recursiveEvaporator(postContent, evap_per_day, threshold, initialContent, iterations);
}
But then I found more sophisticated solution:
return (int)Math.ceil(Math.log(threshold / 100.0) / Math.log(1.0 - evap_per_day / 100.0));
Could you please explain me how does logarithms work here and why we choose natural logarithm?
First of all you have to obtain a clear image of e, that is the base of the natural logarithm.
e - is constant that represents approximation of (1 + 1/n)^n that we call for when speaking about constant growth
We see that newly appeared "addition" participated in further exponentiation.Roughly speaking: e^x is our income after x, where x is t*r (t-time; r-rate)
ln(y) is a reverse operation, we are aimed to know the time over rate we have to spend waiting for y income.
Bringing back the subject of your question
ln(threshold) - is t*r(time * rate)
ln(1 - evap_per_day) - is a t*r to evoparate 90% !but not initial, again we need ln because 90% is constantly decreasing and we chould include it into account.
We divide a product of ln(threshold) by ln(1 - evap_per_day) to get know the time.
So the correct solution is: (int)Math.ceil(Math.log(threshold / 100.0) / (ln(1.0 - evap_per_day / 100.0))
This is a case of using exponential decay and solving for time
The Exponential decay formula is A = A_o(1 - r)^t where A is the final quantity, A_o is the inital quantity, r is the rate of decay and t is the time.For this question we want to know the number of days until the intial amount is at or below a threshold percentage of the initail amount, evaperating at a cetain percentage per day. We can rewrite the equation as so:
(using the percent values for threshold and evapPerDay to make explaination easier)
A_o(threshold) = A_o( 1 - evapPerDay)^t
simplifies to:
threshold = (1 - evapPerDay)^t
now we use logs to solve for t
log(threshold) = log((1- evapPerDay)^t)
use one of the laws of logs to move the t
log(threshold) = t(log(1-evapPerDay))
solve for t
log(threshold)/log(1-evapPerDay) = t
Use ceiling to round up.

How to clamp a value from 0 to infinite to a value from 0 to 1?

I have a program in Java that generates a float value aggressiveness that can be from 0 to infinite. What I need to do is that the higher this float is, the higher there are chances the program fires a function attackPawn().
I already found out that I need the function Math.random(), which gives a random value between 0 and 1. If Math.random() is lower than aggressiveness transformed into a float between 0 and 1, I call the function attackPawn().
But now I am stuck, I can't figure out how I can transform aggressiveness from 0 to infinite to a float which is from 0 to 1, 1 meaning "infinite" aggressiveness and 0 meaning absence of anger.
Any ideas or math equation?
You want a monotonic function that maps [0...infinity] to [0..1]. There are many options:
y=Math.atan(x)/(Math.PI/2);
y=x/(1+x);
y=1-Math.exp(-x);
There are more. And each of those functions can be scaled arbitrarily, given a positive constant k>0:
y=Math.atan(k*x)/(Math.PI/2);
y=x/(k+x);
y=1-Math.exp(-k*x);
There is an infinite number of options. Just pick one that suits your needs.
It is possible to map [0,infinity) to [0,1), but this won't be linear. An example function would be:
y = tan(x * pi / 2);
The problem with this function is that you can't make a correct computer program from that since it is not possible (or easy) to first compute a real big number like 10^5000 and map it down to [0,1).
But a better solution would be to change your definition to something like that:
0 = no aggression
1 = maximum aggression
With this you don't have to map the numbers
Try something like this:
// aggressiveness is a float with a value between 0 and Float.MAX_VALUE or a value of Float.POSITIVE_INFINITY
if (aggressiveness == Float.POSITIVE_INFINITY) {
aggressiveness = 1f;
} else {
aggressiveness = aggressiveness / Float.MAX_VALUE;
}
// aggressiveness is now between 0 and 1 (inclusive)
Though Double class supports infinite value double d=Double.POSITIVE_INFINITY but i dont think you can use it for your arithmatic purpose. Better you define a maximum value and treat it as infinity.
double Min=0;
double Max= Double.MAX_VALUE;
double aggresiveness= Min + (Math.random() * ((Max - Min) + 1));
ps: you can also take aggresiveness as long or int if you don't want it be a double
Try to transform aggressiveness with a function like:
public float function(float aggressiveness) {
if(aggressiveness > 0F) {
return 1 - (1 / aggressiveness);
}
return 0F;
}
This will map your value to the range of [0, 1);

Rounding a double

Hey guys, I am trying to round to 3 decimal places.
I used the following code.
this.hours = Round(hours + (mins / 60), 3);
But it's not working.
Where have I gone wrong?
Thanks
You can use this function:
public static double Round(double number, int decimals)
{
double mod = Math.pow(10.0, decimals);
return Math.round(number * mod ) / mod;
}
First thing is that all your variables are int so the result of your division is also an int, so nothing to Round.
Then take a look to: How to round a number to n decimal places in Java
If mins is an integer, then mins / 60 will result in an integer division, which always results in 0.
Try changing from 60 to 60.0 to make sure that the division is treated as a floating point division.
Example:
int hours = 5;
int mins = 7;
// This gives 5.0
System.out.println(Math.round(1000 * (hours + (mins / 60 ))) / 1000.0);
// While this gives the correct value 5.117. (.0 was added)
System.out.println(Math.round(1000 * (hours + (mins / 60.0))) / 1000.0);
if mins is an integer you have to divide through 60.0 to get a floating number which you can round
try using like follow
this.hours = Round(hours + (((double)mins) / 60), 3);
You can't. Doubles don't have decimal places, because they are binary, not decimal. You can convert it to something that does have decimal places, i.e. a base-ten number, e.g. BigDecimal, and adjust the precision, or you can format it for output with the facilities of java.text, e.g. DecimalFormat, or the appropriate System.out.printf() string.

Categories