VBA writing to file is rounding numeric values - how to prevent? - excel

In the below code I am having problems making sure the file writer does not round my number off to a certain number of decimal places. I need to use a variant because sometimes the value is string and at other times it is a number.
How can I force it to write exactly what the variable is? For example the below code might show 0.00038 and I want to show the exact value.
Dim MyFile1 As Variant
Dim MyNumber as Variant
MyFile0 = "C:/myfile.csv"
fnum0 = FreeFile()
Open MyFile0 For Output As fnum0
MyNumber = 0.0003759656
Print #fnum0, MyNumber

Your code is fine. The issue is with excel. When opening a CSV in excel, including thru VBA, excel detirmines what a cell is. Typically, if it lloks like a number with more then 5 characters it will express it in Scientific notation or rounded to 5 places.
Note sure what you are doing with the CSV file before or where you are getting it from, but here are some options to prevent excel from changing your data:
In VBA use the Workbook.OpenText command to open the CSV with either:
-the all excel cells as text*
-the column stored number with so many decimal places
(note a max of 30 decimal places apply)
-a particular column store as text.
--A full list of option syntax here http://msdn.microsoft.com/en-us/library/office/bb22351(v=office.12).aspx
You may also import your CSV into an excel spreadsheet, it will give you the option to choose data type for each column. Then run the VBA against the excel file.
If you are not doing formulations in excel, I would recomend storing the number as a text string. VBA automatically converts strings of numbers into numeric values when needed.

It's likely that you're experiencing floating point errors. They are are very small errors that occur when numbers are converted from/to base 10 (human) to/from base 2 (computer). For your purposes, you need to determine what it means that two values are not equal. It's not just val1 <> val2 because that won't account for the tiny errors. If you're dealing with money, for instance, you probably don't care about anything less than a penny. So you might determine inequality as ABS(val1 - val2) > .001. You just need to determine what your tolerance for equality is and compare to that standard.

It may be that your number is not being stored as a number in vba, and when you write it Excel converts it. Say you're number is 1.789 and you write it to a cell that is formatted as 'GENERAL'. Excel will write 1.79 (and think that's the number, not even a formatting issue).
What I've discovered, is if you convert the number to a decimal first CDEC(YOURNUMBER), it will write it correctly. For good measure, I also verify that the cell is '.NUMBERFORMAT = "GENERAL'

Related

VBA - Export Sheet as CSV without rounding values in CSV [duplicate]

In the below code I am having problems making sure the file writer does not round my number off to a certain number of decimal places. I need to use a variant because sometimes the value is string and at other times it is a number.
How can I force it to write exactly what the variable is? For example the below code might show 0.00038 and I want to show the exact value.
Dim MyFile1 As Variant
Dim MyNumber as Variant
MyFile0 = "C:/myfile.csv"
fnum0 = FreeFile()
Open MyFile0 For Output As fnum0
MyNumber = 0.0003759656
Print #fnum0, MyNumber
Your code is fine. The issue is with excel. When opening a CSV in excel, including thru VBA, excel detirmines what a cell is. Typically, if it lloks like a number with more then 5 characters it will express it in Scientific notation or rounded to 5 places.
Note sure what you are doing with the CSV file before or where you are getting it from, but here are some options to prevent excel from changing your data:
In VBA use the Workbook.OpenText command to open the CSV with either:
-the all excel cells as text*
-the column stored number with so many decimal places
(note a max of 30 decimal places apply)
-a particular column store as text.
--A full list of option syntax here http://msdn.microsoft.com/en-us/library/office/bb22351(v=office.12).aspx
You may also import your CSV into an excel spreadsheet, it will give you the option to choose data type for each column. Then run the VBA against the excel file.
If you are not doing formulations in excel, I would recomend storing the number as a text string. VBA automatically converts strings of numbers into numeric values when needed.
It's likely that you're experiencing floating point errors. They are are very small errors that occur when numbers are converted from/to base 10 (human) to/from base 2 (computer). For your purposes, you need to determine what it means that two values are not equal. It's not just val1 <> val2 because that won't account for the tiny errors. If you're dealing with money, for instance, you probably don't care about anything less than a penny. So you might determine inequality as ABS(val1 - val2) > .001. You just need to determine what your tolerance for equality is and compare to that standard.
It may be that your number is not being stored as a number in vba, and when you write it Excel converts it. Say you're number is 1.789 and you write it to a cell that is formatted as 'GENERAL'. Excel will write 1.79 (and think that's the number, not even a formatting issue).
What I've discovered, is if you convert the number to a decimal first CDEC(YOURNUMBER), it will write it correctly. For good measure, I also verify that the cell is '.NUMBERFORMAT = "GENERAL'

How to use =LEFT and =LEN function with scientific notation in Excel VBA?

I'm trying to write an Excel macro using VBA that will return only the first 5 numbers in a cell when the length of that cell exceeds 20. The field normally returns 15-digit alphanumeric results (which I need to leave alone) but in certain exceptions will return a 5-digit number with a multitude of zeroes following it (1234500000000000000000000...) which Excel converts into scientific notation (1.2345E+160). I am able to convert the cells to numbers instead of scientific notation and view the whole number.
I've tried to use code such as =IF(LEN(A1)>20,LEFT(A1,5),A1) and it just returns 1.2345E+160. Even though the whole number is displaying, Excel still thinks the cell length is 11 and won't display the first 5 digits.
I've also tried lines such as =IF(A1="E",LEFT(A1,6),A1) thinking it would detect the E, return 1.2345, and I could just remove the decimal points, but that didn't work either (it just returns the original 1.2345E+160).
I got the same results whether the cell was formatted as number or text. Is there a way around this?
Thank you for your time!
You are trying to use string manipulation on a number. Instead use math:
=A1/1E+160
If you do actually want to treat this thing as text, understand that the underlying value being stored is your 12345000000000000... and there is no decimal point in that thing. So you'll have to convert to text and add the decimal:
=LEFT(TEXT(A1,"0"), 1) & "." & MID(TEXT(A1,"0"), 2, 4)
But that's pretty ugly. I would just stick with math.

Decimal number in string-data-type with large amount of decimals always interpreted as large integer (regional decimal separator issue)

Background: I'm receiving data for my Excel application from an API in JSON format. For this matter I'm receiving numerical values as a string, as everything sent in JSON naturally is a text format - and so does VBA also interpret it. As I'm located in Denmark, using a different decimal separator than the native on in Excel (my Danish version utilizes , as separator rather than .).
Case:
This is causing quite a bit of trouble as Excel interprets this as a thousand-separator when converting the string to a number.
Searching for answers I've found that the best solution, normally, is to convert the string to double when using VBA, utilizing CDbl(string to convert to number).
This usually is the case, but in my case I'm receiving a number with a lot of decimals such as: "9.300000190734863".
When doing a CDbl("9.300000190734863") this results in a very large integer: 9,30000019073486E+15
Also, I don't think utilizing a replace() approach is feasible in my case as I might also have data that uses both decimal- and thousand separators at the same time, making my results prone to replacement errors.
However, inserting the string value directly into a cell within Excel converts the number correctly to 9,30000019073486 in my case.
Question: Can it be right that there's no way to mimic, or tap into, this functionality that Excel obviously is using when inserting the string into a cell?
I've searched for quite some time now, and I haven't found any solution other than the obvious: inserting the value into a cell. The problem here is that it's giving me some performance overhead which I would rather avoid.
You can swap the positions of the periods and commas in your input prior to casting as a double, in three steps:
Replace commas with 'X' (or some other value that won't appear in your data)
Replace periods with commas
Replace 'X' with periods

Why do Excel values in parentheses become negative values?

A colleague and I encountered a behavior in Excel which isn't clear to us.
Background:
We have a tool which converts an Excel sheet into a table format. The tool calculates the formulas which are in excel and replaces variables inside it with specific values.
The excel tool is used by one of our customers who use values like (8) or (247).
These Value are automatically translated by excel to -8 or -247.
Question:
I saw that many people want to display negative numbers in parentheses. But why would Excel change values in parentheses to a negative number?
I know that I could simply change the cell config to text and this would solve the problem but I wonder if there is a reason for the behavior, since there seems to be no mathematical reason for this.
Its simply the different format of cells you are bringing the "values from" and "pasting to". ..... numbers with parentheses are in cells with "accounting" format and negatives are stored in general or standard number formated cells. To resolve you can change the format of destination cells to accounting using cell formatting as number>accounting.
To answer the why, it's because accountants put negative numbers in brackets for readability
Unfortunately, this is one of the excel feature/bugs that helps some folks and frustrates others. When opening a file or pasting content, excel will immediately and always try to parse any values into formats it deems appropriate, which can mess up data like:
Zip Codes / Tel. # → Numeric: 05401 → 5401
Fractions → Dates: 11/20 → Nov, 20th YYYY
Std. Errors → Negative Numbers: (0.1) → -0.1
For some workarounds , see Stop Excel from automatically converting certain text values to dates
Once the file is open/pasted, the damage is already done. At that point, your best bet is:
Updating the field and displaying as text (appending with ') to prevent re-casting
Formatting the field if the operation wasn't lossy and is just presenting the info differently
Running a clean if/else to pad or other convert your data based on the identified errors
Specific to displaying values back in parens, if excel is converting them and treating them like negative numbers (which may or may not be the appropriate way to actually store the data), you can apply a different format to positive and negative numbers to wrap back in parens.
It is standard practice to write negative values as numbers in parentheses, especially in accounting. This makes negative values stand out much more than a simple negative hyphen; compare -1 and (1).
Excel is a tool very commonly used by accountants and supports accountant-style spreadsheets. Therefore, entering (100) means having a value of -100, even if there is no minus hyphen!
Here is a fun fact, if you enter (-10), Excel will treat it as normal text.

Reading mix between numeric and non-numeric data from excel into Matlab

I have a matrix where the first column contains dates and the first row contains maturities which are alpha/numeric (e.g. 16year).
The rest of the cells contain the rates for each day, which are double precision numbers.
Now I believe xlsread() can only handle numeric data so I think I will need something else or a combination of functions?
I would like to be able to read the table from excel into MATLAB as one array or perhaps a struct() so that I can keep all the data together.
The other problem is that some of the rates are given as '#N/A'. I want the cells where these values are stored to be kept but would like to change the value to blank=" ".
What is the best way to do this? Can it be done as part of the input process?
Well, from looking at matlab reference for xlsread you can use the format
[num,txt,raw] = xlsread(FILENAME)
and then you will have in num a matrix of your data, in txt the unreadable data, i.e. your text headers, and in raw you will have all of your data unprocessed. (including the text headers).
So I guess you could use the raw array, or a combination of the num and txt.
For your other problem, if your rates are 'pulled' from some other source, you can use
=IFERROR(RATE DATA,"")
and then there will be a blank instead of the error code #N\A.
Another solution (only for Windows) would be to use xlsread() format which allows running a function on your imported data,
[num,txt,raw,custom] = xlsread(filename,sheet,xlRange,'',functionHandler)
and let the function replace the NaN values with blank spots. (and you will have your output in the custom array)

Resources