Mule ESB, formatting decimal format from expression node - json

Prevously I had a result from a Database Connection SQL statement that resembled the following:
[{"BALANCE":111.11},{"BALANCE":222.12},{"BALANCE":444.30}]
And I used the following contents of an expression node to calculate the sum:
sum = 0;
foreach (row : message.payload) {
sum += row['BALANCE'];
}
message.payload = sum;
This did not quite work out, but notice below that there are no quotes around the numeric variable that was returned
777.5299999999999994315658113919199
From an excellent answer from a previous thread, I switched to the following expression node contents:
sum = 0;
foreach (row : message.payload) {
sum += row['BALANCE'];
}
message.payload = new java.text.DecimalFormat("#.##").format(sum);
This resulted the accurate result below:
"777.53"
My only problem is that it has quotes around the number. How can I eliminate the quotes?
Thanks

The real fix to your problem is the following: do not use floating point numbers to store currency amounts. This is prone to rounding errors (as you've experienced above) and it turns out people don't like to lose cents here and there.
Read https://stackoverflow.com/a/3730040/387927 for more on this.
So fix the database to store only integers, for example in cents, 111111 instead of 111.11, and only perform integer calculations on these cents.
Or review the DB query to return java.math.BigDecimal instances instead of the floats or doubles it seems to be returning. That way you would have no adverse rounding playing tricks on you.
Any other approach where you first would go through a lossy floating point data type and then perform rounding (like in user1760178's answer), will expose you to rounding issues.

You may try converting the sum to BigDecimal and then set scale on it to 2.
message.payload = new BigDecimal(sum).setScale(2,java.math.RoundingMode.CEILING)
This keeps your payload as number instead of a String.
Hope this helps.

Related

How to convert exponential number to decimal numbers in action script 3?

I am facing the problem on multiplying two decimal number in flex.
When i am multiplying two decimal number the result is like a exponential number so i don't know how to get the decimal number as a result instead of getting an exponential number.
I am using the following codes to make a multiplication:
var num1:Number = 0.00005;
var num2:Number = 0.000007;
var result:Number = num1 * num2;
And in result variable i am getting the value as 3.5000000000000003E-10.
So i don't know how to get decimal number as result instead of getting an exponential number as above.
If anybody have knowledge how to resolve this problem please help me to solve.
You need to use the .toPrecision(precision:uint) method available in the Number class. This method takes one parameter which is :
precision:uint — An integer between 1 and 21, inclusive, that
represents the desired number of digits to represent in the resulting
string.
So simply do :
trace(result.toPrecision(2));
And you should get an output of 0.00000000035
Official documentation here :
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Number.html#toPrecision()
Hope this helps. Cheers.

Strip decimals in SSRS expression without rounding

In my report I'm trying to remove the decimals without rounding. I'll be using this to set the minimum value in the vertical axis of the area chart.
So I tried =Format(98.56, "N0"), but this returns 99, which is incorrect. It should return 98.
I've been searching specifically for SSRS, but most of the results are for tsql.
My question: How can I remov decimals in SSRS without rounding?
Thanks
Try using "Floor". It effective rounds down to the nearest integer. You'll find this under the Math functions.
=Floor(Fields!Number.Value)
Note, there's also a Floor function in Transact-SQL that works the same way in case you need to do some of the processing in your SQL script.
Update based on request in comments
If you wanted to achieve the same result after the decimal point, all you need is a little algebra.
=Floor((Fields!Number.Value*10))/10
That should turn 99.46 into 99.4. Given that it shaves off the remainder, you could then tack on any additional zeroes you wanted.
I ended up converting to Int. The following expression in SSRS returns 98:
=Int(98.56)
I know the question is quite old, but as I ended up here having the same question I would like to share my answer:
While FLOOR and CEILING are fine if you take extra measures to handle numbers <0 or know they are always >=0, the easiest way to simply strip off the decimals is to use
=Fix(Fields!Number.Value)
FIX only returns the integer part of a number, without any rounding or transformation. For negative numbers Int rounds up.
Source: Examples for Fix, Floor and Ceiling
Source: Difference between Int and Fix

AS3 parseInt() method limitations

I have this issue in converting a HEX string to Number in as3
I have a value
str = "24421bff100317"; decimal value = 10205787172373271
but when I parseInt it I get
parseInt(str, 16) = 10205787172373272
Can anyone please tell me what am I doing wrong here
Looks like adding one ("24421bff100318") works fine. I have to assume that means this is a case of precision error.
Because there are only a finite amount of numbers that can be represented with the memory available, there will be times that the computer is estimating. This is common when working with decimals and very large numbers. It's visible, for example, in this snippet where apparently the computer can't add basic decimals:
for(var i=0;i<3;i+=0.2){
trace(i);
}
There are a few workarounds if accuracy at this level is critical, namely using datatypes that store more information ("long" instead of "int" in Java - I believe "Number" might work in AS3 but I have not tested it for your scenario) or if that fails, breaking the numbers down into smaller parts and adding them together.
For further reading to understand this topic (since I do think it's fascinating), look up "precision errors" and "data types".

The correct way to manipulate doubles on MYSQL (precision)?

I have a 1-cent-auction website that increases bids by 1 cent on every bid
The current_bid field is a DOUBLE on mysql that represents the bid in dollars, and i need to avoid cases like 0.2 + 0.1 = 0.299999999
(not sure if it's the right result format but you get the idea)
I have had lots of cases other than with these two numbers because of precision..
Now, here is my code : (i am hoping its correct and efficient, otherwise, i am open to your ideas)
UPDATE `auctions` SET
`current_bid` = ROUND(ROUND(`current_bid` * 100) + 1)/100
...
Is it too late to switch to DECIMAL? Floating point column types provide approximate values; it's a well known fact and it's by design.

Generating unique codes that are different in two digits

I want to generate unique code numbers (composed of 7 digits exactly). The code number is generated randomly and saved in MySQL table.
I have another requirement. All generated codes should differ in at least two digits. This is useful to prevent errors while typing the user code. Hopefully, it will prevent referring to another user code while doing some operations as it is more unlikely to miss two digits and match another existing user code.
The generate algorithm works simply like:
Retrieve all previous codes if any from MySQL table.
Generate one code at a time.
Subtract the generated code with all previous codes.
Check the number of non-zero digits in the subtraction result.
If it is > 1, accept the generated code and add it to previous codes.
Otherwise, jump to 2.
Repeat steps from 2 to 6 for the number of requested codes.
Save the generated codes in the DB table.
The algorithm works fine, but the problem is related to performance. It takes a very long to finish generating the codes when requesting to generate a large number of codes like: 10,000.
The question: Is there any way to improve the performance of this algorithm?
I am using perl + MySQL on Ubuntu server if that matters.
Have you considered a variant of the Luhn algorithm? Luhn is used to generate a check digit for strings of numbers in lots of applications, including credit card account numbers. It's part of the ISO-7812-1 standard for generating identifiers. It will catch any number that is entered with one incorrect digit, which implies any two valid numbers differ in a least two digits.
Check out Algorithm::LUHN in CPAN for a perl implementation.
Don't retrieve the existing codes, just generate a potential new code and see if there are any conflicting ones in the database:
SELECT code FROM table WHERE abs(code-?) regexp '^[1-9]?0*$';
(where the placeholder is the newly generated code).
Ah, I missed the generating lots of codes at once part. Do it like this (completely untested):
my #codes = existing_codes();
my $frontwards_index = {};
my $backwards_index = {};
for my $code (#codes) {
index_code($code, $frontwards_index);
index_code(reverse($code), $backwards_index);
}
my #new_codes = map generate_code($frontwards_index, $backwards_index), 1..10000;
sub index_code {
my ($code, $index) = #_;
push #{ $index{ substr($code, 0, length($code)/2) } }, $code;
return;
}
sub check_index {
my ($code, $index) = #_;
my $found = grep { ($_ ^ $code) =~ y/\0//c <= 1 } #{ $index{ substr($code, 0, length($code)/2 } };
return $found;
}
sub generate_code {
my ($frontwards_index, $backwards_index) = #_;
my $new_code;
do {
$new_code = sprintf("%07d", rand(10000000));
} while check_index($new_code, $frontwards_index)
|| check_index(reverse($new_code), $backwards_index);
index_code($new_code, $frontwards_index);
index_code(reverse($new_code), $backwards_index);
return $new_code;
}
Put the numbers 0 through 9,999,999 in an augmented binary search tree. The augmentation is to keep track of the number of sub-nodes to the left and to the right. So for example when your algorithm begins, the top node should have value 5,000,000, and it should know that it has 5,000,000 nodes to the left, and 4,999,999 nodes to the right. Now create a hashtable. For each value you've used already, remove its node from the augmented binary search tree and add the value to the hashtable. Make sure to maintain the augmentation.
To get a single value, follow these steps.
Use the top node to determine how many nodes are left in the tree. Let's say you have n nodes left. Pick a random number between 0 and n. Using the augmentation, you can find the nth node in your tree in log(n) time.
Once you've found that node, compute all the values that would make the value at that node invalid. Let's say your node has value 1,111,111. If you already have 2,111,111 or 3,111,111 or... then you can't use 1,111,111. Since there are 8 other options per digit and 7 digits, you only need to check 56 possible values. Check to see if any of those values are in your hashtable. If you haven't used any of those values yet, you can use your random node. If you have used any of them, then you can't.
Remove your node from the augmented tree. Make sure that you maintain the augmented information.
If you can't use that value, return to step 1.
If you can use that value, you have a new random code. Add it to the hashtable.
Now, checking to see if a value is available takes O(1) time instead of O(n) time. Also, finding another available random value to check takes O(log n) time instead of... ah... I'm not sure how to analyze your algorithm.
Long story short, if you start from scratch and use this algorithm, you will generate a complete list of valid codes in O(n log n). Since n is 10,000,000, it will take a few seconds or something.
Did I do the math right there everybody? Let me know if that doesn't check out or if I need to clarify anything.
Use a hash.
After generating a successful code (not conflicting with any existing code), but that code in the hash table, and also put the 63 other codes that differ by exactly one digit into the hash.
To see if a randomly generated code will conflict with an existing code, just check if that code exists in the hash.
Howabout:
Generate a 6 digit code by autoincrementing the previous one.
Generate a 1 digit code by incrementing the previous one mod 10.
Concatenate the two.
Presto, guaranteed to differ in two digits. :D
(Yes, being slightly facetious. I'm assuming that 'random' or at least quasi-random is necessary. In which case, generate a 6 digit random key, repeat until its not a duplicate (i.e. make the column unique, repeat until the insert doesn't fail the constraint), then generate a check digit, as someone already said.)