I am using jxl-2.6.3.jar.
I want to display bigdecimals, which are up to 1 decimal point.
If i write like below, then 1.2 is displayed as "1.2" , but 1.0 appears as "1." .
I need 0 as well in case of 1.0, i.e "1.0" instead of simply "1." .
BigDecimal number = new BigDecimal(1.0);
NumberFormat dp1 = new NumberFormat("#.#");
WritableCellFormat format = new WritableCellFormat(dp1);
workSheet.addCell(new Number(1, 1, number.doubleValue(),format));
Thanks
You should use the number format "#.0". A "#" character indicates that a digit should be there only if necessary to represent the number, and a "0" character indicates that a digit must be there, even if it's unnecessary to represent the number. For further reference, please see the Excel format symbols.
The "#.0" format will work whether you are using NumberFormat in JXL or you are creating a data format string with DataFormat in Apache POI.
Related
I have a large text file with no headers with fields delimited by a fixed width. All numeric fields are padded with zeros. I want to import this into Alteryx using field settings from a flat file.
Some of my fields should have the format Fixed Decimal, for example the "Regular Cost" column is a fixed decimal 9.04 - 5 decimal places before the decimal point and four following. Input example is "000026300". Desired output is 2.63.
I can't figure out the Length and Scale requirements for this to work.
Length = 9, Scale = 4 gives the error
Regular Cost: "000023600.0000" was too long to fit in this FixedDecimal.
Example image
Apparently it doesn't like the missing decimal point. If you read the file as a string, then add the decimal to the correct location in the string, e.g. read it in and force the field length to 10, then use the formula...
Left([Field_1],5) + "." + Left(Right([Field_1],4),3)
... it will look as expected. Then you can map it to a Double or a FixedDecimal 10.4
I have an excel file with the value 6228480018362050000 the exported csv looks like this...
Int,Bigint,String
1,6228480018362050000,Very big
When I try running the following code...
InputStream inp = new FileInputStream("/.../test.xlsx");
DataFormatter df = new DataFormatter(true);
df.formatCellValue(WorkbookFactory.create(inp).getSheetAt(0).getRow(1).getCell(1));
I get 6228480018362049500 which is the wrong number because precision is hosed. Is there a way to get the actual value?
If we put long numbers into Excel cells, then those numbers will be truncated to 15 significant digits. This is because Excel does not know such things like big integers. It has only floating point to store numeric values. And with those it follows the IEEE 754 specification. But some numbers cannot be stored as floating point numbers according to the IEEE 754 specification. With your example the 6228480018362050000, which is 6.22848001836205E+018, cannot be stored as such. It will be 6.2284800183620495E+018 or 6228480018362049500 according to IEEE 754 specification.
Microsoft's knowledge base mentions: "Excel follows the IEEE 754 specification on how to store and calculate floating-point numbers. Excel therefore stores only 15 significant digits in a number, and changes digits after the fifteenth place to zeroes."
This is not the whole truth. In reality at least with Office OpenXML (*.xlsx) it stores the values according to IEEE 754 specification and not only 15 significant digits. With your example it stores <v>6.2284800183620495E+18</v>. But thats secondary. Because even if it would store 6.22848001836205E+018, somewhere this must be reconverted to floating point and then it will be 6.2284800183620495E+18 again. Excel does the same while opening the workbook. It converts <v>6.2284800183620495E+18</v> to floating point and then it only displays 15 significant digits.
So if you really need to store the 6228480018362050000 as a number in Excel, then the only way to get the same results as in Excel is to do the same as Excel. To do so we can use BigDecimal and it's round method which is able to use a MathContext with setted precision.
Example:
import org.apache.poi.ss.usermodel.*;
import java.io.*;
import java.math.BigDecimal;
import java.math.MathContext;
class ReadExcelBigNumbers {
public static void main(String[] args) throws Exception{
for (int i = 0; i < 10; i++) {
String v = "6.2284800183620" + i + "E+018";
double d = Double.parseDouble(v);
System.out.print(v + "\t");
System.out.print(d + "\t");
BigDecimal bd = new BigDecimal(d);
v = bd.round(new MathContext(15)).toPlainString();
System.out.println(v);
}
InputStream inp = new FileInputStream("test.xlsx");
Workbook wb = WorkbookFactory.create(inp);
for (int i = 1; i < 9; i++) {
double d = wb.getSheetAt(0).getRow(i).getCell(1).getNumericCellValue();
BigDecimal bd = new BigDecimal(d);
String v = bd.round(new MathContext(15)).toPlainString();
System.out.println(v);
}
}
}
The first part prints:
6.22848001836200E+018 6.2284800183620004E18 6228480018362000000
6.22848001836201E+018 6.2284800183620096E18 6228480018362010000
6.22848001836202E+018 6.2284800183620198E18 6228480018362020000
6.22848001836203E+018 6.2284800183620301E18 6228480018362030000
6.22848001836204E+018 6.2284800183620403E18 6228480018362040000
6.22848001836205E+018 6.2284800183620495E18 6228480018362050000
6.22848001836206E+018 6.2284800183620598E18 6228480018362060000
6.22848001836207E+018 6.22848001836207E18 6228480018362070000
6.22848001836208E+018 6.2284800183620803E18 6228480018362080000
6.22848001836209E+018 6.2284800183620905E18 6228480018362090000
There you can see the difference between wanted floating point value, real floating point value according IEEE 754 specification and reformatted BigDecimal. As you see only the 6.22848001836207E+018 can be stored according to the IEEE 754 specification directly.
The second part does the same using the following Excel sheet:
Another possible workaround is mentioned in the knowledge base article : "To work around this behavior, format the cell as text, then type the numbers. The cell can then display up to 1,024 characters. ". This is good if the numbers are not really numbers but Identifiers for example or some other strings where the digits are only meant as characters. Calculations with such "Text-Numbers" are of course not possible without reconverting them to floating point which will bring the problem again.
There is no change (loss or gain) of precision between 6228480018362050000 and 6228480018362049500. They are simply two different decimal presentations of the same internal binary value, which in decimal is exactly 6228480018362049536, by the way.
Regardless of the cell format, Excel displays (not "stores") only up to the first 15 significant digits, rounding any digits to the right [1].
However, other applications and file formats show up to the first 17 significant digits (or more), which is really what the IEEE 754 standard requires in order to represent every binary value [2]. Apparently, that is true of Apache POI and OpenXML.
You can demonstrate this by doing the following.
In Excel, enter 6228480018362050000. Save as XML.
Open the XML file in Notepad. Note that the Cell/Data element shows 6.2284800183620495E+18, which is 6228480018362049500.
Open the XML file in Excel. Note that Excel still displays 6228480018362050000 in the Formula Bar and in the cell formatted as Number.
It is true that Excel truncates manually-entered numbers (including those read from CSV and TXT files) to the first 15 significant digits, replacing any digits to the right with zeros. But Excel VBA does not.
So for another demonstration, enter the following in VBA, then execute the procedure.
Sub doit()
Range("a1:a2").NumberFormat = "0"
Range("a1") = CDbl("6228480018362050000")
Range("a2") = CDbl("6228480018362049536")
Columns("a").AutoFit
Range("b2") = "=match(a1,a2,0)"
End Sub
Note that A1 and A2 display 6228480018362050000. B2 displays 1, indicating that the internal binary values are an exact match, and VBA does not truncate after the first 15 significant digits.
Explanation....
Excel and most applications use IEEE 754 double-precision to represent numeric values. The binary representation is the sum of 53 consecutive powers of 2 ("bits") times an exponential factor.
Consequently, only integers up to 9007199254740992 (2^53) can be represented exactly. (But note that Excel displays 9007199254740990 for =2^53 because of its 15-significant-digit formatting limitation.)
Most larger integers can only be approximated.
And that is true of most decimal fractions as well, regardless of the number of significant digits. That is part of the reason why =10.1-10 displays 0.0999999999999996 in the Formula Bar and in the cell formatted with 16 decimal places (15 significant digits).
But beware: a calculated value that displays as 6228480018362050000 might differ from the actual internal binary value.
For example, if you enter 6228480018362050000 into A1 and the formula =6228480018362050000+1600 into A2, both A1 and A2 display 6228480018362050000.
But =MATCH(A1,A2,0) returns #N/A, which indicates that the internal binary values are not an exact match.
And the XML file would show 6.2284800183620516E+18 in the Data element corresponding to the Cell element for A2, which is 6228480018362051600. The actual internal binary value, in decimal, is exactly 6228480018362051584.
(FYI, the Excel equal operator ("=") does not compare the internal binary values. Instead, it compares the values rounded to 15 significant digits. So =(A1=A2) returns TRUE misleadingly. It is intended to be a feature; but it is implemented inconsistently.)
If you copy A2 and paste-value into A3, =MATCH(A1,A3,0) continues to return #N/A. But if you subsequently "edit" A3 (e.g. press f2, then Enter), =MATCH(A1,A3,0) returns 1. The internal value of A3 has been changed to the binary representation of 6228480018362050000.
I wonder if that is actually the mysterious problem that you encountered, and you inadvertently oversimplified it with your example.
Does that help?
[1] Cell format does not affect the internal binary value with two exceptions: (1) when Precision As Displayed is set, which is almost never recommended; and (2) when the cell value is calculated, and the worksheet is saved in CSV or TXT file, then re-open or imported in Excel.
[2] Although IEEE 754 specifies that 17 significant decimal digits are the minimum needed to represent all binary values, that does not mean that only 17 significant decimal digits are "stored". As demonstrated above, 6228480018362049500 is actually stored as exactly 6228480018362049536.
I am using Apache POI 3.9 for XLS/XLSX file processing.
In the XLS sheet, there is a column with numeric value like "3000053406".
When I read it with POI with..
cell.getNumericCellValue()
It gives me value like "3.00E+08". This create huge problem in my application.
How can I set the number formatting while reading data in Apcahe POI ?
There is a way that I know is to set the column as "text" type. But I want to know if there is any other way at Apache POI side while reading the data. OR can we format it by using simple java DecimalFormatter ?
This one comes up very often....
Picking one of my past answers to an almost identical question
What you want to do is use the DataFormatter class. You pass this a cell, and it does its best to return you a string containing what Excel would show you for that cell. If you pass it a string cell, you'll get the string back. If you pass it a numeric cell with formatting rules applied, it will format the number based on them and give you the string back.
For your case, I'd assume that the numeric cells have an integer formatting rule applied to them. If you ask DataFormatter to format those cells, it'll give you back a string with the integer string in it.
Problem can be strictly Java-related, not POI related, too.
Since your call returns a double,
double val = cell.getNumericCellValue();
You may want to get this
DecimalFormat df = new DecimalFormat("#");
int fractionalDigits = 2; // say 2
df.setMaximumFractionDigits(fractionalDigits);
double val = df.format(val);
Creating a BigDecimal with the double value from the numeric cell and then using the
BigDecimal.toPlainString()
function to convert it to a plain string and then storing it back to the same cell after erasing the value solved the whole problem of exponential representation of numeric values.
The below code solved the issue for me.
Double dnum = cellContent.getNumericCellValue();
BigDecimal bd = new BigDecimal(dnum);
System.out.println(bd.toPlainString());
cellContent.setBlank();
cellContent.setCellValue(bd.toPlainString());
System.out.println(cellContent.getStringCellValue());
long varA = new Double(cellB1.getNumericCellValue()).longValue();
This will bring the exact value in variable varA.
I am putting a string into excel. The string is often only numeric digits but can have alpha characters or hypens etc.
When I don't set the number format or set it like this
(Where xlSheet(0) is Excel.Worksheet)
xlSheet(0).Columns("N:N").EntireColumn.Columns.NumberFormat = "#"
It outputs in scientific notation.
When I use this code:
xlSheet(0).Columns("N:N").EntireColumn.Columns.NumberFormat = "0"
It rounds up the number to the nearest 100,000 so that the last five digits are 0's when they shouldn't be.
Should be: 1539648751235678942
But is: 1539648751235600000
The cells that have a hyphen or a letter aren't affected and work fine.
Any help would be greatly appreciated.
EDIT:
I add the data like this:
I loop through and put in xlSheet(0).Cells(i, 14) = rs!value_number
Where rs is my ADODB.Recordset
EDIT2: Herbert Sitz got it by adding an apostrophe before the text! Thanks everyone.
I think problem is that the number you're trying to enter can't be accommodated exactly by Excel. Excel has limitations on what numbers it display/represent because of the way numbers are stored internally. In Excel's case numbers are limited to 15 digit precision (see http://office.microsoft.com/en-us/excel-help/excel-specifications-and-limits-HP010073849.aspx ), which is not enough to represent your number.
You can enter the number as a string ("152..42") and all digits will be displayed, but you won't be able to perform exact mathematical operations with it.
For numbers, Excel can only handle 15 significant digits.
If you want to store a number that is more than 15 digits long without losing data, you have to store the data as text.
Doing what you've been doing will resolve the issue:
You can do either of the following to add your numbers as text:
xlSheet(0).Cells(i, 14).Numberformat = "#"
xlSheet(0).Cells(i, 14) = rs!value_number
Or
xlSheet(0).Cells(i, 14) = "'" & rs!value_number
I have price column in which the prices are displayed in 3 decimals and 4 decimals places, for example 123.456 or 123.4357.
So irrespective of the number of decimal places i want the value to be with only two decimals.
So i am selecting the column and in the VBA i am using Selection.NumberFormat = "0.00"
Which is resulting me the rounded value i.e when i format 123.456 and 123.4357 to 0.00 i am getting 123.46 and 123.44 but i want it to be 123.46 and 123.43.
So just wondering is there a way we can just trim the values instead of rounding.
Please give me some sample examples.
Thank you in advance.
Excel has a built-in function, trunc, that should do the trick for you.
This is what I placed in a1:b2.
123.456 =trunc(A1,2)
123.4357 =trunc(A2,2)
This will display
123.456 123.45
123.4357 123.43
You could treat the result as a string and extract the number of characters you need as in:
dim a as double
dim s as string
a = 123.4357
s = MID(a,1,FIND(".",a))&MID(a,FIND(".",a)+1,2)
I don't believe there is a built in mask that will truncate without rounding, you could instead use another column containing =TRUNC(A1, 2).