DecimalFormat with RoundingMode.HALF_UP - math

Having a simple code
import java.math.RoundingMode
import java.text.DecimalFormat
fun main(args: Array<String>) {
val f = DecimalFormat("#.##").apply { roundingMode = RoundingMode.HALF_UP }
println(f.format(-0.025f))
println(f.format(-0.015f))
println(f.format(-0.005f))
println(f.format(0.005f))
println(f.format(0.015f))
println(f.format(0.025f))
}
I got the following output:
-0,03 <-- ok
-0,01 <-- expecting -0,02
-0 <-- expecting -0,01
0 <-- expecting 0,01
0,01 <--- expecting 0,02
0,03 <-- ok
Do I correctly understand RoundingMode.HALF_UP meaning?
P.S.
I had found, that using doubles instead of floats solve the problem. So println(f.format(0.005.toDouble())) works, giving expected 0.1.

What the documentation says about RoundingMode.HALF_UP is:
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
While that might look like the behavior you're looking for, these are decimal floats, and they have a hard time being represented in memory. There's a great read on it on the Oracle site.
So, it seems that -0.005 and -0.015 both are closer (nearest neighbor) to -0.01 than anything else, so they both are formatted as -0.01. To make your code do what you want it do to, is to change your rounding mode to:
roundingMode = RoundingMode.UP
The output of running that is:
-0.03
-0.02
-0.01
0.01
0.02
0.03
Which is exactly what you expected. If you do want your code to work, you can use the following approach though:
import java.math.BigDecimal
import java.math.RoundingMode
import java.text.DecimalFormat
fun main(args: Array<String>) {
val f = DecimalFormat("#.##").apply { roundingMode = RoundingMode.HALF_UP }
println(f.format( BigDecimal("-1000.045")))
println(f.format( BigDecimal("-1000.035")))
println(f.format( BigDecimal("-1000.025")))
println(f.format( BigDecimal("-1000.015")))
println(f.format( BigDecimal("-1000.005")))
}

Never ever use float or double if you want exact numbers to show up. If you round and want the rounding to happen on a solid base, you don't want float or double neither ;-)
Your sample using double would also give wrong results. Your sample using BigDecimal will give the results you expect. So... stick with BigDecimal if you want to be safe(r).
fun main(args: Array<String>) {
val f = DecimalFormat("#.##").apply { roundingMode = RoundingMode.HALF_UP }
println(f.format(BigDecimal("-0.025")))
println(f.format(BigDecimal("-0.015")))
println(f.format(BigDecimal("-0.005")))
println(f.format(BigDecimal("0.005")))
println(f.format(BigDecimal("0.015")))
println(f.format(BigDecimal("0.025")))
}

Related

Xquery transform string to same number but with decimal dot

I am working with xQuery version 1.0 and I'm trying to transform a string of numbers to the same number but with a decimal dot. But here's my problem. The decimal dot should be placed according to a certain element value.
The message I'm trying to transform:
<AMOUNT
<VALUE>34221</VALUE>
<NUMOFDEC>1</NUMOFDEC>
<SIGN>+</SIGN>
<CURRENCY>EUR</CURRENCY>
<DRCR>C</DRCR>
</AMOUNT>
What I'm trying to achieve:
<prefix:Rates
<prefix:Amount currency="EUR">3422.1</prefix:Amount>
</prefix:Rates>
What did I try:
<prefix:Rates>
<prefix:Amount currency="{ data(AMOUNT/CURRENCY) }">{ ((data(AMOUNT/VALUE) div 10)) }</prefix:Amount>
</prefix:Rates>
The problem with the above transformation is that it's not dynamic. But as you can see there is an element <NUMOFDEC>1</NUMOFDEC>. Can I use that value in a certain formula to place the decimal dot according to this value?
EDIT (19th october 2022):
As a another user mentioned, there is recursion. Let's take this recursion from user #Michael Kay:
declare function f:two-to-the($n as xs:integer) as xs:integer {
if ($n = 0) then 1 else 2 * f:two-to-the($n - 1)
};
So how will I be able to apply this to my situation?
(div math:pow(10, AMOUNT/NUMOFDEC)) might do but I don't recall whether XQuery 1 supports the math namespace mathematical functions, namespace is e.g. math="http://www.w3.org/2005/xpath-functions/math", it might depend on your XQuery processor, I guess.
So I found a solution with an if-else statement. Unfortunately as another user mentioned, the mat:pow fucntion is not supported by Xquery 1.0.
Solution:
<prefix:Amount>{
(for $decimal in (data(AMOUNT/NUMOFDEC))
return if ($decimal = '1')
then ((data(AMOUNT/VALUE)) div 10)
else if ($decimal = '2')
then ((data(AMOUNT/VALUE)) div 100)
else ($decimal = '3')
then ((data(AMOUNT/VALUE)) div 1000)
else ((data(AMOUNT/VALUE)) div 10000))
}</prefix:Amount>
Is it fully dynamic? no. But it will do the trick for now.
EDIT (19th october 2022): The following recursion works!:
declare function xf:ten-to-the($decimal as xs:integer) as xs:integer {
if ($decimal = 0) then 1 else 10 * xf:ten-to-the($decimal - 1)
};

Time subtraction in Aurelia

I would like to print the duration of an event that occurs between 'startDateTime' and 'endDateTime', expressed in minutes or seconds (if less than 1 minute).
In other words, ${startDateTime | dateFormat:"YYYY-MM-DD HH:mm"} is 2018-09-07 11:57 and ${startDateTime | dateFormat:"YYYY-MM-DD HH:mm"} is 2018-09-07 13:00.
What I would like to print is 63 minutes.
In PHP, I would do ->getTimestamp(), but in Aurelia I have no clue what to even try.
I did test with something like ${endDateTime| dateFormat:"HH:mm:ss" - startDateTime| dateFormat:"HH:mm:ss"} but this can't work as it doesn't convert the entire date time to seconds or minutes...
Therefore, is there a clean solution I can implement in my view?
I solved it using a value converter.
import moment = require("moment");
export class DurationValueConverter {
public toView(startAt, endAt) {
if (!endAt) {
// If end date is missing, use the current date and time.
endAt = moment();
}
const duration = moment.duration(moment(endAt).diff(moment(startAt)));
return duration.humanize();
}
}
Usage: ${startedAt | duration:endedAt}
What you want to have is relative time, It's on its way to browsers, but for now, you will have to use polyfill / library for it. One you can find is from yahoo: https://github.com/yahoo/intl-relativeformat

Overriding a conditional variable in UnrealScript with a child class in Deus Ex?

I'm actually using the original Deus Ex game from the year 2000. I created a child class of "DeusEx.Flare" and called it "rflare" and saved it to my own package. I have successfully compiled it, and it works, but not the way I intended. I want to override the function "LifeSpan = 30" and give it "LifeSpan = 120". The problem is the documentation. There practically is none. And the documentation I can find generally is too confusing and does not give good enough examples for what I'm tryng to do. here is the code. I know I'm supposed to be using the "super" expression but I have exhausted all the ways I know how to use it. I simply cannot get it to work. However, I can get it to work if I dont' mind throwing both the normal flare (which goes out in 30 seconds) and my own flare, which only drops to the ground without a sound but will in fact last 120 seconds. So my code would end up throwing 2 flares. 1 normal flare that goes out in 30 sec. and the other that does last 120 but does not get thrown like the normal flare does.
here is the code from DeusEx.Flare script that I'm trying to change.
function LightFlare()
{
local Vector X, Y, Z, dropVect;
local Pawn P;
if (gen == None)
{
LifeSpan = 30;
}
}
My first attempt was to copy this and change it in my own package. It worked but again, it shot 2 flares, 1 normal and 1 that sorta worked. I want to do only one. So here is my attempt at correcting the code.
function LightFlare()
{
Super(Flare).LightFlare();
if (gen == None)
{
LifeSpan = 120;
}
}
All this does is spawn the normal flare, with no difference in the time it lasts. Can someone please help me?
I would suggest copying the LightFlare function in it's entirety from the parent class and not calling super. You don't want the original function to run, as that will mess with the lifetime variable.
For instance:
class RFlare extends Flare;
function LightFlare()
{
local Vector X, Y, Z, dropVect;
local Pawn P;
// Original function here, change lifetime when specified.
if (gen == None)
{
LifeSpan = 120;
}
}
defaultproperties
{
}

Prompting the user for an int, not a string, until they do even if it's a negative number

I'm writing a program and it asks the user to input a number, I need to make sure that that number is and actual number not a string. That number can be positive or negative. I've tried using .isnumerical() and .isdigit() but they won't except negative numbers.
lowest_num = input("What would you like the lowest possible number to be?")
while lowest_num.isdigit() is not True:
lowest_num = (input("Please only enter a number : ")).lower()
Thanks for the help in advance
lowest_num = int(input("What would you like the lowest possible number to be?")) should do it
Alright, try this:
number_not_entered = True
num = 0
while number_not_entered:
try:
num = int(input("enter num"))
number_not_entered = False
except ValueError:
print("please try again")
Note that catching all exceptions is generally a bad practice.
Use isnan() function from numpy library. First import numpy and then use numpy.isnan(a number)

How can I find the duration of a song when given its ID using XQuery?

First off, yes this is homework - please suggest where I am going wrong,but please do not do my homework for me.
I am learning XQuery, and one of my tasks is to take a list of song ID's for a performance and determine the total duration of the performance. Given the snippits below, can anyone point me to where I can determine how to cross reference the songID from the performance to the duration of the song?
I've listed my attempts at the end of the question.
my current XQuery code looks like:
let $songIDs := doc("C:/Users/rob/Downloads/A4_FLOWR.xml")
//SongSet/Song
for $performance in doc("C:/Users/rob/Downloads/A4_FLOWR.xml")
//ContestantSet/Contestant/Performance
return if($performance/SongRef[. =$songIDs/#SongID])
then <performanceDuration>{
data($performance/SongRef)
}</performanceDuration>
else ()
Which outputs:
<performanceDuration>S005 S003 S004</performanceDuration>
<performanceDuration>S001 S007 S002</performanceDuration>
<performanceDuration>S008 S009 S006</performanceDuration>
<performanceDuration>S002 S004 S007</performanceDuration>
Each S00x is the ID of a song, which us found in the referenced xml document (partial document):
<SongSet>
<Song SongID="S001">
<Title>Bah Bah Black Sheep</Title>
<Composer>Mother Goose</Composer>
<Duration>2.99</Duration>
</Song>
<Song SongID="S005">
<Title>Thank You Baby</Title>
<Composer>Shania Twain</Composer>
<Duration>3.02</Duration>
</Song>
</SongSet>
The performance section looks like:
<Contestant Name="Fletcher Gee" Hometown="Toronto">
<Repertoire>
<SongRef>S001</SongRef>
<SongRef>S002</SongRef>
<SongRef>S007</SongRef>
<SongRef>S010</SongRef>
</Repertoire>
<Performance>
<SongRef>S001</SongRef>
<SongRef>S007</SongRef>
<SongRef>S002</SongRef>
</Performance>
</Contestant>
My Attempts
I thought I would use nested loops, but that fails:
let $songs := doc("C:/Users/rob/Downloads/A4_FLOWR.xml")
//SongSet/Song
for $performance in doc("C:/Users/rob/Downloads/A4_FLOWR.xml")
//ContestantSet/Contestant/Performance
return if($performance/SongRef[. =$songs/#SongID])
for $song in $songIDs
(: gives an error in BaseX about incomplete if :)
then <performanceDuration>{
data($performance/SongRef)
}</performanceDuration>
else ()
--Edit--
I've fixed the inner loop, however I am getting all the songs durations, not just the ones that match id's. I have a feeling that this is due to variable scope, but I'm not sure:
let $songs := doc("C:/Users/rob/Downloads/A4_FLOWR.xml")//SongSet/Song
for $performance in doc("C:/Users/rob/Downloads/A4_FLOWR.xml")//ContestantSet/Contestant/Performance
return if($performance/SongRef[. =$songs/#SongID])
then <performanceDuration>{
for $song in $songs
return if($performance/SongRef[. =$songs/#SongID])
then
sum($song/Duration)
else ()
}</performanceDuration>
else ()
}
Output:
<performanceDuration>2.99 1.15 3.15 2.2 3.02 2.25 3.45 1.29 2.33 3.1</performanceDuration>
Your immediate problem is syntactic: you've inserted your inner loop between the condition and the keyword 'then' in a conditional. Fix that first:
return if ($performance/SongRef = $songs/#SongID) then
<performanceDuration>{
(: put your inner loop HERE :)
}</performanceDuration>
else ()
Now think yourself into the situation of the query evaluator inside the performanceDuration element. You have the variable $performance, you can find all the song references using $performance/SongRef, and for each song reference in the performance element, you can find the corresponding song element by matching the SongRef value with $songs/#SongID.
My next step at this point would be to ask myself:
For a given song reference, how do I find the song element for that song, and then the duration for that song?
Is there a way to get the sum of some set of durations? Is there, for example, a sum() function? (I'm pretty sure there is, but at this point I always pull up the Functions and Operators spec and look it up to be sure of the signature.)
What type does the duration info have? I'd expect it to be minutes and seconds, and I'd be worrying about duration arithmetic, but your sample makes it look like decimals, which will be easy.

Resources