It's a simple-looking question:
Given that native-sized integers are the best for arithmetic, why doesn't C# (or any other .NET language) support arithmetic with the native-sized IntPtr and UIntPtr?
Ideally, you'd be able to write code like:
for (IntPtr i = 1; i < arr.Length; i += 2) //arr.Length should also return IntPtr
{
arr[i - 1] += arr[i]; //something random like this
}
so that it would work on both 32-bit and 64-bit platforms. (Currently, you have to use long.)
Edit:
I'm not using these as pointers (the word "pointer" wasn't even mentioned)! They can be just treated as the C# counterpart of native int in MSIL and of intptr_t in C's stdint.h -- which are integers, not pointers.
In .NET 4, arithmetic between a left hand operand of type IntPtr and a right hand operand of integer types (int, long, etc) is supported.
[Edit]:
As other people have said, they are designed to represent pointers in native languages (as implied by the name IntPtr). It's fine to claim you're using them as native integers rather than pointers, but you can't overlook that one of the primary reasons the native size of an integer ever matters is for use as a pointer. If you're performing mathematical operations, or other general functions that are independent from the processor and memory architecture that your code is running on, it is arguably more useful and intuitive to use types such as int and long where you know their fixed size and upper and lower bounds in every situation regardless of hardware.
Just as the type IntPtr is designed to represent a native pointer, the arithmetic operations are designed to represent logical mathematical operations that you would perform on a pointer: adding some integer offset to a native pointer to reach a new native pointer (not that adding two IntPtrs is not supported, and nor is using IntPtr as the right hand operand).
Maybe native-sized integers make for the fastest arithmetic, but they certainly don't make for the most error-free programs.
Personally I hate programming with integer types whose sizes I do not know when I sit down to start typing (I 'm looking at you, C++), and I definitely prefer the peace of mind the CLR types give you over the very doubtful and certainly conditional performance benefit that using CPU instructions tailored to the platform might offer.
Consider also that the JIT compiler can optimize for the architecture the process is running on, in contrast to a "regular" compiler which has to generate machine code without having access to this information. The JIT compiler might therefore generate code just as fast because it knows more.
I imagine I 'm not alone in thinking this, so it might count for a reason.
I can actually think of one reason why an IntPtr (or UIntPtr) would be useful: accessing elements of an array requires native-sized integers. Though native integers are never exposed to the programmer, they are internally used in IL. Something like some_array[index] in C# will actually compile down to some_array[(int)checked((IntPtr)index)] in IL. I noticed this after disassembling my own code with ILSpy. (The index variable is 64-bit in my code.) To verify that the disassembler wasn't making a mistake, Microsoft's own ILDASM tool shows the existence of conv.u and conv.i instructions within my assembly. Those instructions convert integers to the system's native representation. I don't know what the performance implication is having all these conversion instructions in the IL code, but hopefully the JIT is smart enough to optimize the performance penalty away; if not, the next best thing is to allow manipulating native integers without conversions (which, in my opinion, might be the main motivation to use a native type).
Currently, the F# language allows the use of nativeint and and its unsigned counterpart for arithmetic. However, arrays can only be indexed by int in F# which means nativeint is not very useful for the purposes of indexing arrays.
If it really bothers you that much, write your own compiler that lifts restrictions on native integer use, create your own language, write your code in IL, or tweak the IL after compiling. Personally, I think it's a bad idea to squeeze out extra performance or save memory by using native int. If you wanted your code to fit the system like a glove, you'd best be using a lower level language with support for processor intrinsics.
.Net Framework tries not to introduce operations that can't be explained. I.e. there is no DateTime + DateTime because there is no such concept as sum of 2 dates. The same reasoning applies to pointer types - there is no concept of sum of 2 pointers. The fact that IntPtr is stored as platform depenedent int value does not really matter - there are a lot of other types that internally stored as basic values (again DateTime can be represented as long).
Because that's not a "safe" way of handling memory addressing. Pointer arithmetic can lead to all sorts of bugs and memory addressing problems that C# is designed explicitly to avoid.
Related
I've been reading a lot about floating-point determinism in .NET, i.e. ensuring that the same code with the same inputs will give the same results across different machines. Since .NET lacks options like Java's fpstrict and MSVC's fp:strict, the consensus seems to be that there is no way around this issue using pure managed code. The C# game AI Wars has settled on using Fixed-point math instead, but this is a cumbersome solution.
The main issue appears to be that the CLR allows intermediate results to live in FPU registers that have higher precision than the type's native precision, leading to impredictably higher precision results. An MSDN article by CLR engineer David Notario explains the following:
Note that with current spec, it’s still a language choice to give
‘predictability’. The language may insert conv.r4 or conv.r8
instructions after every FP operation to get a ‘predictable’ behavior.
Obviously, this is really expensive, and different languages have
different compromises. C#, for example, does nothing, if you want
narrowing, you will have to insert (float) and (double) casts by hand.
This suggests that one may achieve floating-point determinism simply by inserting explicit casts for every expression and sub-expression that evaluates to float. One might write a wrapper type around float to automate this task. This would be a simple and ideal solution!
Other comments however suggest that it isn't so simple. Eric Lippert recently stated (emphasis mine):
in some version of the runtime, casting to float explicitly gives a
different result than not doing so. When you explicitly cast to float,
the C# compiler gives a hint to the runtime to say "take this thing
out of extra high precision mode if you happen to be using this
optimization".
Just what is this "hint" to the runtime? Does the C# spec stipulate that an explicit cast to float causes the insertion of a conv.r4 in the IL? Does the CLR spec stipulate that a conv.r4 instruction causes a value to be narrowed down to its native size? Only if both of these are true can we rely on explicit casts to provide floating point "predictability" as explained by David Notario.
Finally, even if we can indeed coerce all intermediate results to the type's native size, is this enough to guarantee reproducibility across machines, or are there other factors like FPU/SSE run-time settings?
Just what is this "hint" to the runtime?
As you conjecture, the compiler tracks whether a conversion to double or float was actually present in the source code, and if it was, it always inserts the appropriate conv opcode.
Does the C# spec stipulate that an explicit cast to float causes the insertion of a conv.r4 in the IL?
No, but I assure you that there are unit tests in the compiler test cases that ensure that it does. Though the specification does not demand it, you can rely on this behaviour.
The specification's only comment is that any floating point operation may be done in a higher precision than required at the whim of the runtime, and that this can make your results unexpectedly more accurate. See section 4.1.6.
Does the CLR spec stipulate that a conv.r4 instruction causes a value to be narrowed down to its native size?
Yes, in Partition I, section 12.1.3, which I note you could have looked up yourself rather than asking the internet to do it for you. These specifications are free on the web.
A question you didn't ask but probably should have:
Is there any operation other than casting that truncates floats out of high precision mode?
Yes. Assigning to a static field, instance field or element of a double[] or float[] array truncates.
Is consistent truncation enough to guarantee reproducibility across machines?
No. I encourage you to read section 12.1.3, which has much interesting to say on the subject of denormals and NaNs.
And finally, another question you did not ask but probably should have:
How can I guarantee reproducible arithmetic?
Use integers.
The 8087 Floating Point Unit chip design was Intel's billion dollar mistake. The idea looks good on paper, give it an 8 register stack that stores values in extended precision, 80 bits. So that you can write calculations whose intermediate values are less likely to lose significant digits.
The beast is however impossible to optimize for. Storing a value from the FPU stack back to memory is expensive. So keeping them inside the FPU is a strong optimization goal. Inevitable, having only 8 registers is going to require a write-back if the calculation is deep enough. It is also implemented as a stack, not freely addressable registers so that requires gymnastics as well that may produce a write-back. Inevitably a write back will truncate the value from 80-bits back to 64-bits, losing precision.
So consequences are that non-optimized code does not produce the same result as optimized code. And small changes to the calculation can have big effects on the result when an intermediate value ends up needing to be written back. The /fp:strict option is a hack around that, it forces the code generator to emit a write-back to keep the values consistent, but with the inevitable and considerable loss of perf.
This is a complete rock and a hard place. For the x86 jitter they just didn't try to address the problem.
Intel didn't make the same mistake when they designed the SSE instruction set. The XMM registers are freely addressable and don't store extra bits. If you want consistent results then compiling with the AnyCPU target, and a 64-bit operating system, is the quick solution. The x64 jitter uses SSE instead of FPU instructions for floating point math. Albeit that this added a third way that a calculation can produce a different result. If the calculation is wrong because it loses too many significant digits then it will be consistently wrong. Which is a bit of a bromide, really, but typically only as far as a programmer looks.
I am doing a project in C#, which could benefit from a linear algebra package. I've looked at the ones out there, but I don't really want to pay, or I found them not very good. So I decided to write my own.
I read that C++ arrays are much faster than C# arrays, but that it was possible to get similar performance using pointer arrays in C#, although they are considered "unsafe." I'm curious to know how C++ pointers differ, and if the "unsafe-ness" applies to C++ as well, or if they are two fundamentally different things.
Both C# (unsafe) pointers and C++ (raw) pointers have the following characteristics:
They allow you to reference an address in a given address space.
They allow you to perform simple arithmetic operations (addition and subtraction) on them, involving integers as offsets.
They allow you to dereference whatever they point to as data of a particular type.
Wrong usage of them can invoke undefined behavior, making it exclusively your responsibility to ensure that you're using them correctly.
In that sense, and regardless of any minor differences (like syntax, pinning, etc), C# pointers and C++ pointers are pretty much the same programming concept. Therefore, they lend themselves to static analysis pretty much equally and thus they are equally safe or unsafe. So the fact that C# explicitly calls this construct out as unsafe doesn't make the equivalent C++ construct "safe". Rather, the ability to use "unsafe" code is "always on" in C++.
As an example, consider the case where you attempt to access an array using an index that's out of bounds:
With a C# array you will get an exception when using the indexer syntax and you will invoke undefined behavior when using a pointer and an offset.
With a C-style array in C++ you will invoke undefined behavior when using either the indexer syntax or a pointer and an offset (because those two syntaxes are equivalent for C-style arrays).
With a C++11 std::array you will get an exception when using array::at and you will invoke undefined behavior when using the indexer syntax.
Roughly speaking (and it is a very crude approximation), a C# unsafe pointer is the same sort of thing as a C++ pointer.
With both, there is a lot more responsibility on the programmer to get it right whereas with normal C# if you get things wrong, the worst that will happen is that an exception will be thrown. The run-time checks that give those guarantees cost performance, but if you switch them off - you are on your own.
In particular, unsafe in C# means can break out of the managed sandbox and execute native code. This then means your managed code can generate unmanaged crashes. This is also why unsafe code is not allowed without full trust (but you probably don't have to deal with partial trust code anymore).
You're probably thinking how can I run unmanaged code with an int * in C#. Easy: deliberate stack smashing. Assign it to the address of an integer on the stack and write to the next few integers the address of a byte array containing native code.
unsafe means that .Net grants you access to memory that you did not necessarily allocate. The bound checking is turned off which allows some optimizations in the JIT compiler.
In general, pointers are the same in C++, that is they grant you access to any region of memory. You can implement bound-checking with operator overloading, but it isn't the default for pointers.
I've been reading a lot about floating-point determinism in .NET, i.e. ensuring that the same code with the same inputs will give the same results across different machines. Since .NET lacks options like Java's fpstrict and MSVC's fp:strict, the consensus seems to be that there is no way around this issue using pure managed code. The C# game AI Wars has settled on using Fixed-point math instead, but this is a cumbersome solution.
The main issue appears to be that the CLR allows intermediate results to live in FPU registers that have higher precision than the type's native precision, leading to impredictably higher precision results. An MSDN article by CLR engineer David Notario explains the following:
Note that with current spec, it’s still a language choice to give
‘predictability’. The language may insert conv.r4 or conv.r8
instructions after every FP operation to get a ‘predictable’ behavior.
Obviously, this is really expensive, and different languages have
different compromises. C#, for example, does nothing, if you want
narrowing, you will have to insert (float) and (double) casts by hand.
This suggests that one may achieve floating-point determinism simply by inserting explicit casts for every expression and sub-expression that evaluates to float. One might write a wrapper type around float to automate this task. This would be a simple and ideal solution!
Other comments however suggest that it isn't so simple. Eric Lippert recently stated (emphasis mine):
in some version of the runtime, casting to float explicitly gives a
different result than not doing so. When you explicitly cast to float,
the C# compiler gives a hint to the runtime to say "take this thing
out of extra high precision mode if you happen to be using this
optimization".
Just what is this "hint" to the runtime? Does the C# spec stipulate that an explicit cast to float causes the insertion of a conv.r4 in the IL? Does the CLR spec stipulate that a conv.r4 instruction causes a value to be narrowed down to its native size? Only if both of these are true can we rely on explicit casts to provide floating point "predictability" as explained by David Notario.
Finally, even if we can indeed coerce all intermediate results to the type's native size, is this enough to guarantee reproducibility across machines, or are there other factors like FPU/SSE run-time settings?
Just what is this "hint" to the runtime?
As you conjecture, the compiler tracks whether a conversion to double or float was actually present in the source code, and if it was, it always inserts the appropriate conv opcode.
Does the C# spec stipulate that an explicit cast to float causes the insertion of a conv.r4 in the IL?
No, but I assure you that there are unit tests in the compiler test cases that ensure that it does. Though the specification does not demand it, you can rely on this behaviour.
The specification's only comment is that any floating point operation may be done in a higher precision than required at the whim of the runtime, and that this can make your results unexpectedly more accurate. See section 4.1.6.
Does the CLR spec stipulate that a conv.r4 instruction causes a value to be narrowed down to its native size?
Yes, in Partition I, section 12.1.3, which I note you could have looked up yourself rather than asking the internet to do it for you. These specifications are free on the web.
A question you didn't ask but probably should have:
Is there any operation other than casting that truncates floats out of high precision mode?
Yes. Assigning to a static field, instance field or element of a double[] or float[] array truncates.
Is consistent truncation enough to guarantee reproducibility across machines?
No. I encourage you to read section 12.1.3, which has much interesting to say on the subject of denormals and NaNs.
And finally, another question you did not ask but probably should have:
How can I guarantee reproducible arithmetic?
Use integers.
The 8087 Floating Point Unit chip design was Intel's billion dollar mistake. The idea looks good on paper, give it an 8 register stack that stores values in extended precision, 80 bits. So that you can write calculations whose intermediate values are less likely to lose significant digits.
The beast is however impossible to optimize for. Storing a value from the FPU stack back to memory is expensive. So keeping them inside the FPU is a strong optimization goal. Inevitable, having only 8 registers is going to require a write-back if the calculation is deep enough. It is also implemented as a stack, not freely addressable registers so that requires gymnastics as well that may produce a write-back. Inevitably a write back will truncate the value from 80-bits back to 64-bits, losing precision.
So consequences are that non-optimized code does not produce the same result as optimized code. And small changes to the calculation can have big effects on the result when an intermediate value ends up needing to be written back. The /fp:strict option is a hack around that, it forces the code generator to emit a write-back to keep the values consistent, but with the inevitable and considerable loss of perf.
This is a complete rock and a hard place. For the x86 jitter they just didn't try to address the problem.
Intel didn't make the same mistake when they designed the SSE instruction set. The XMM registers are freely addressable and don't store extra bits. If you want consistent results then compiling with the AnyCPU target, and a 64-bit operating system, is the quick solution. The x64 jitter uses SSE instead of FPU instructions for floating point math. Albeit that this added a third way that a calculation can produce a different result. If the calculation is wrong because it loses too many significant digits then it will be consistently wrong. Which is a bit of a bromide, really, but typically only as far as a programmer looks.
I'm trying to learn digital image processing, I found my friend using c#. There is a very important reason why he using C#: There is unsafe keyword in c# and the performance of his code(algorithm part) can reach 75% of same code in c++, which is good enough for him.
He encourages me to turn to c#, but I'm java programmer of many years. I know there is a Unsafe class in java too, but I have never used of it, not sure if the performance is as good as C#.
So I want to know the performance of Unsafe in java, and is it a good idea to use Java for image processing?
UPDATE
Just using unsafe code for some performance-aware task, not use it everywhere.
Unsafe means you can avoid all the overheads in a managed environment. All the range and type checking, Garbage collection, reflection etc. Whether your code will be faster using unsafe all depends on what you wrote. I dare say the main optimisation point would be processing large blocks of raw memory as opposed to say a list of pixel classes or structs which OO would lead you towards.
I love C#, but choosing one language over another because of a feature, that has a very limited scope seems a very weak argument to me. Don't pick a language based on your friend's opinions, but based on your needs and preferences! Programming language is just a tool. You'd seriously dump years of experiences just like that? Use the language you're most comfortable with.
Check this discussion it comes up with both plus and negative points about it here
Though this one taken from C# article but I think it applies well for Java too - check here
In unsafe code or in other words unmanaged code it is possible to declare and use pointers. But the question is why do we write unmanaged code? If we want to write code that interfaces with the operating system, or want to access memory mapped device or want to implement a time critical algorithm then the use of pointer can give lots of advantages.
But there are some disadvantages of using pointers too. If pointers were chosen to be 32 bit quantities at compile time, the code would be restricted to 4gig of address space, even if it were run on a 64 bit machine. If pointers were chosen at compile time to be 64 bits, the code could not be run on a 32 bit machine.
Can anyone explain to me what the benefits and and drawbacks of the two different approaches are?
When a double or long in Java is volatile, §17.7 of the Java Language Specification requires that they are read and written atomically. When they are not volatile, they can be written in multiple operations. This can result, for example, in the upper 32 bits of a long containing a new value, while the lower 32 bits still contain the old value.
Atomic reads and writes are easier for a programmer to reason about and write correct code with. However, support for atomic operations might impose a burden on VM implementers in some environments.
I don't know the reason why volatile cannot be applied to 64-bit ints in C#, but You can use Thread.VolatileWrite to do what you want in C#.
The volatile keyword is just syntactic sugar on this call.
excerpt:
Note:
In C#, using the volatile modifier on a field guarantees that all access to that field
uses Thread.VolatileRead or Thread.VolatileWrite.
The syntactic sugar (keyword) applies to 32-bit ints, but you can use the actual method calls on 64-bit ints.
I guess it comes down to what the memory model can guarantee. I don't know a vast amount about the CLI memory model (that C# has to use), but I know it'll guarantee 32 bits... but not 64 (although it'll guarantee a 64-bit reference on x64 - the full rules are in §17.4.3 of ECMA 334v4) . So it can't be volatile. You still have the Interlocked methods, though (such as long Interlocked.Exchange(ref long,long) and long Interlocked.Increment(ref long) etc).
I'm guessing that longs can't be volatile in C# because they are larger than 32-bits and can not be accessed in an atomic operation. Even though they would not be stored in a register or CPU cache, because it takes more than one operation to read or write the value it is possible for one thread to read the value while another is in the process of writing it.
I believe that there is a difference between how Java implements volatile fields and how DotNet does, but I'm not sure on the details. Java might use a lock on the field to prevent the problem that C# has.