I am using ArrayFire library for signal processing. I am just curious about how to make more efficient my code. I read vectorization guide in docs, but i just ended up using gfor construct. Is it possible to improve efficiency ? Is there a better way for vectorization ? ( I hope there is :)
Note : I am aiming CUDA performance.
Here is the code which i am trying to improve :
#include <arrayfire.h>
#include <stdio.h>
#include <af/util.h>
static int proc_size = 1024;
static int fft_size = proc_size * 4;
static int staves = 288;
static int beams = 256;
static af::array S;
static af::array B;
static af::array R;
void fn()
{
gfor ( af::seq i, fft_size )
R( i , af::span ) = matmul( S( i , af::span ) , B( af::span , af::span , i ) );
}
int main(int, char **)
{
S = af::randn( fft_size , staves , c32 );
gfor ( af::seq i, fft_size )
S( i , af::span ) = af::randn( 1 , staves , c32 );
B = af::randn( staves , beams , fft_size , af::dtype::c32 );
R = af::constant( af::cfloat { 0 , 0 } , fft_size , beams );
try
{
af::setDevice( 0 );
af::info();
double time = af::timeit(fn);
printf( "Took %f secs.\n" , time );
}
catch (const af::exception &ex)
{
fprintf(stderr, "%s\n", ex.what());
throw;
}
return 0;
}
Related
I need to download the file after a pause. But I do not know how to implement it correctly using https://github.com/yhirose/cpp-httplib . But the problem is that when the download resumes, the server starts sending me the file first. Question: how do I tell the server the size of the piece that I have already downloaded, so that the server sends me only the necessary part?
My code:
std::string body;
httplib::Client cli( url, port );
cli.set_follow_location( true );
int file_size = is_part_of_file ? GetFileSize( result_file_name.c_str() ) : 0; // it is downloaded part of the file
int last_percent;
auto res = cli.Get(
file_path.c_str(), httplib::Headers(),
[ & ]( const httplib::Response& response )
{
( void )response;
return *is_download;
},
[ & ]( const char* data, size_t data_length )
{
body.append( data, data_length );
return *is_download;
},
[ & ]( uint64_t len, uint64_t total )
{
int percent = ( int )( len * 100 / total );
if( last_percent != percent )
{
*p_percent = ( ( float )percent / 100 );
}
last_percent = percent;
return *is_download;
} );
if( res )
{
std::ofstream out( result_file_name, std::ios::binary | std::ios::app );
out << body;
out.close();
}
else
{
if( is_part_of_file )
{
std::ofstream out( result_file_name, std::ios::binary | std::ios::app );
out << body;
out.close();
}
return false;
}
I have written a C++ code using opencv, I converted the C++ code as a "DLL" and I need to call a method from this dll in python which receives cv::Mat as datatype. But I am getting error here. The below are the samples of C++ code and python code.
On googling I found we need to use Boost library but am not sure how to convert Python mat to C++ cv::Mat and how to make interface between them.
C++ dll code:
DLLEXPORT int FromPython ( cv :: Mat InputSrc) {
imshow ( "FromPython", InputSrc );
return 0;
}
Python Code
import cv2 as cv
from ctypes import cdll
cap = cv.VideoCapture(0)
while(1):
ret, frame = cap.read()
cv.imshow('frame',frame)
mydll = cdll.LoadLibrary('C:\Users\Documents\FromPythonDLL.dll')
i = mydll.FromPython(frame)
print(i)
k = cv.waitKey(1) & 0xff
if k == 27:
break
cap.release()
cv.destroyAllWindows()
You can have a look at the OpenCV Python wrapper. In the OpenCV folder in modules/python/src2/cv2.cpp (depending on the version, I use OpenCV 2.4) there are some functions called pyopencv_to used by the OpenCV Python wrapper. One of those is used to convert PyObject to cv::Mat. Your "FromPython" function needs to get PyObject as input. I personally use boost::python::object to pass the numpy arrays returned by the Python OpenCV functions to the C++ function/class. You should end up having something like this in C++:
///PythonToOCV.h
#ifndef __PYTHONTOOCV_H_INCLUDED__
#define __PYTHONTOOCV_H_INCLUDED__
#include <iostream>
#include <Python.h>
#include <boost/python.hpp>
#include "numpy/ndarrayobject.h"
#include "opencv2/core/core.hpp"
/////////////////////////////////////////////////////////////////////////////
/// \brief Import Numpy array. Necessary to avoid PyArray_Check() to crash
void doImport( );
int failmsg( const char *fmt, ... );
static size_t REFCOUNT_OFFSET = ( size_t )&((( PyObject* )0)->ob_refcnt ) +
( 0x12345678 != *( const size_t* )"\x78\x56\x34\x12\0\0\0\0\0" )*sizeof( int );
static inline PyObject* pyObjectFromRefcount( const int* refcount )
{
return ( PyObject* )(( size_t )refcount - REFCOUNT_OFFSET );
}
static inline int* refcountFromPyObject( const PyObject* obj )
{
return ( int* )(( size_t )obj + REFCOUNT_OFFSET );
}
class NumpyAllocator : public cv::MatAllocator
{
public:
NumpyAllocator( ) { }
~NumpyAllocator( ) { }
void allocate( int dims, const int* sizes, int type, int*& refcount,
uchar*& datastart, uchar*& data, size_t* step );
void deallocate( int* refcount, uchar* datastart, uchar* data );
};
/////////////////////////////////////////////////////////////////////////////
/// \brief Convert a numpy array to a cv::Mat. This is used to import images
/// from Python.
/// This function is extracted from opencv/modules/python/src2/cv2.cpp
/// in OpenCV 2.4
int pyopencv_to( const PyObject* o, cv::Mat& m, const char* name = "<unknown>", bool allowND=true );
#endif //__PYTHONTOOCV_H_INCLUDED__
///PythonToOCV.cpp
#include "PythonToOpenCV.h"
void doImport( )
{
import_array( );
}
int failmsg( const char *fmt, ... )
{
char str[1000];
va_list ap;
va_start( ap, fmt );
vsnprintf( str, sizeof( str ), fmt, ap );
va_end( ap );
PyErr_SetString( PyExc_TypeError, str );
return 0;
}
void NumpyAllocator::allocate( int dims, const int* sizes, int type, int*& refcount, uchar*& datastart, uchar*& data, size_t* step )
{
int depth = CV_MAT_DEPTH( type );
int cn = CV_MAT_CN( type );
const int f = ( int )( sizeof( size_t )/8 );
int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
int i;
npy_intp _sizes[CV_MAX_DIM+1];
for( i = 0; i < dims; i++ )
_sizes[i] = sizes[i];
if( cn > 1 )
{
/*if( _sizes[dims-1] == 1 )
_sizes[dims-1] = cn;
else*/
_sizes[dims++] = cn;
}
PyObject* o = PyArray_SimpleNew( dims, _sizes, typenum );
if( !o )
CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
refcount = refcountFromPyObject(o);
npy_intp* _strides = PyArray_STRIDES(o);
for( i = 0; i < dims - (cn > 1); i++ )
step[i] = (size_t)_strides[i];
datastart = data = (uchar*)PyArray_DATA(o);
}
void NumpyAllocator::deallocate( int* refcount, uchar* datastart, uchar* data )
{
if( !refcount )
return;
PyObject* o = pyObjectFromRefcount(refcount);
Py_INCREF(o);
Py_DECREF(o);
}
// Declare the object
NumpyAllocator g_numpyAllocator;
int pyopencv_to(const PyObject* o, cv::Mat& m, const char* name, bool allowND )
{
// to avoid PyArray_Check() to crash even with valid array
doImport( );
if(!o || o == Py_None)
{
if( !m.data )
m.allocator = &g_numpyAllocator;
return true;
}
if( !PyArray_Check(o) )
{
failmsg("%s is not a numpy array", name);
return false;
}
// NPY_LONG (64 bit) is converted to CV_32S (32 bit)
int typenum = PyArray_TYPE(o);
int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S :
typenum == NPY_INT || typenum == NPY_LONG ? CV_32S :
typenum == NPY_FLOAT ? CV_32F :
typenum == NPY_DOUBLE ? CV_64F : -1;
if( type < 0 )
{
failmsg("%s data type = %d is not supported", name, typenum);
return false;
}
int ndims = PyArray_NDIM(o);
if(ndims >= CV_MAX_DIM)
{
failmsg("%s dimensionality (=%d) is too high", name, ndims);
return false;
}
int size[CV_MAX_DIM+1];
size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
const npy_intp* _sizes = PyArray_DIMS(o);
const npy_intp* _strides = PyArray_STRIDES(o);
bool transposed = false;
for(int i = 0; i < ndims; i++)
{
size[i] = (int)_sizes[i];
step[i] = (size_t)_strides[i];
}
if( ndims == 0 || step[ndims-1] > elemsize ) {
size[ndims] = 1;
step[ndims] = elemsize;
ndims++;
}
if( ndims >= 2 && step[0] < step[1] )
{
std::swap(size[0], size[1]);
std::swap(step[0], step[1]);
transposed = true;
}
if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] )
{
ndims--;
type |= CV_MAKETYPE(0, size[2]);
}
if( ndims > 2 && !allowND )
{
failmsg("%s has more than 2 dimensions", name);
return false;
}
m = cv::Mat(ndims, size, type, PyArray_DATA(o), step);
if( m.data )
{
m.refcount = refcountFromPyObject(o);
m.addref(); // protect the original numpy array from deallocation
// (since Mat destructor will decrement the reference counter)
};
m.allocator = &g_numpyAllocator;
if( transposed )
{
cv::Mat tmp;
tmp.allocator = &g_numpyAllocator;
transpose(m, tmp);
m = tmp;
}
return true;
}
Then the function where you can access to cv::Mat will look like:
/// fromPython.h
#ifndef __FROMPYTHON_H_INCLUDED__
#define __FROMPYTHON_H_INCLUDED__
#include "PythonToOCV.h"
#include <boost/python.hpp>
int fromPython( boost::python::object &frame );
#endif //__FROMPYTHON_H_INCLUDED__
/// fromPython.cpp
#include "fromPython.h"
int fromPython( boost::python::object &frame )
{
cv::Mat image;
// this is the function from modules/python/src2/cv2.cpp (the third parameter might be ArgInfo in later OpenCV versions)
pyopencv_to( frame.ptr( ), image, "info", true );
///
/// HERE code using cv::Mat image
///
return 1;
}
This function to be accessible from Python needs to be wrapped in a BOOST_PYTHON_MODULE. Soemthing like:
#include "fromPython.h"
using namespace boost::python;
/// This function needs to be included to pass PyObjects as numpy array ( http://mail.python.org/pipermail/cplusplus-sig/2006-September/011021.html )
void* extract_pyarray( PyObject* x )
{
return PyObject_TypeCheck( x, &PyArray_Type ) ? x : 0;
}
BOOST_PYTHON_MODULE( myWrapper )
{
// This function needs to be included to pass PyObjects as numpy array ( http://mail.python.org/pipermail/cplusplus-sig/2006-September/011021.html )
boost::python::converter::registry::insert( &extract_pyarray, type_id<PyArrayObject>( ) );
def fromPython( "fromPython", &fromPython );
}
Then in Python you can call your function from the Python module created by the Boost wrapper. I am using Linux so I compile the code above to get an dynamic library (.so). I am not sure how different it is in Windows. I can access to the module from the dynamic library as:
import myWrapper
import cv2
def myFunct():
cap = cv2.VideoCapture(0)
while(1):
ret,frame = cap.read()
myWrapper.fromPython(frame)
You can probably avoid the use of Boost but I haven't tried other ways and I found Boost convenient to wrap C++ classes.
NOTE: I haven't tested this code as I stripped it from a project but I hope it can still be useful.
I have a Visual Studio 2008 C++03 project using Lua 5.2.1 where I would like to allow a Lua script to use Win32 iteration functions (FindFirst*, FindNext*, etc...)
For example, I'd like to be able to list the running processes:
#include <tlhelp32.h>
#pragma comment( lib, "toolhelp.lib" )
static int process_iter_next( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( ::Process32Next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
return 1;
}
return 0;
}
static int process_iter_first( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( ::Process32First( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
// How do I replace the closure with process_iter_next?
return 1;
}
return 0;
}
static int l_list( lua_State *L )
{
HANDLE* h = ( HANDLE* )lua_newuserdata( L, sizeof( HANDLE ) );
luaL_getmetatable( L, "process.list" );
lua_setmetatable( L, -2 );
*h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0 );
if( INVALID_HANDLE_VALUE == *h )
luaL_error( L, "Failed to list processes. EC: %d", ::GetLastError() );
lua_pushcclosure( L, process_iter_first, 1 );
return 1;
}
static int process_gc( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, 1 );
if( INVALID_HANDLE_VALUE != h )
::CloseToolhelp32Snapshot( h );
return 0;
}
extern "C" int luaopen_process( lua_State *L )
{
static const luaL_Reg process[] = {
{ "list", l_list },
{ NULL, NULL }
};
luaL_newmetatable( L, "process.list" );
lua_pushstring( L, "__gc" );
lua_pushcfunction( L, process_gc );
lua_settable( L, -3 );
luaL_newlib( L, process );
return 1;
}
My Lua script:
for p in process.list() do
print(p)
end
When I run this, only the process_iter_first will be called. How do I replace the c-closure created in l_list with process_iter_next when Process32First succeeds?
EDIT per #Mud's suggestion*
static int process_iter( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
typedef BOOL ( *PFN_ProcessIter )( HANDLE, LPPROCESSENTRY32 );
PFN_ProcessIter next = ( PFN_ProcessIter )lua_touserdata( L, lua_upvalueindex( 2 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
lua_pushlightuserdata( L, Process32Next );
// not sure how to use this function. The docs are not enlightening.
// lua_setupvalue( L, ???, ??? );
// This looked like a good idea from the docs, but it causes an access violation
// lua_setuservalue( L, lua_upvalueindex( 2 ) );
return 1;
}
return 0;
}
static int l_list( lua_State *L )
{
HANDLE* h = ( HANDLE* )lua_newuserdata( L, sizeof( HANDLE ) );
luaL_getmetatable( L, "process.list" );
lua_setmetatable( L, -2 );
*h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0 );
if( INVALID_HANDLE_VALUE == *h )
luaL_error( L, "Failed to list processes. EC: %d", ::GetLastError() );
lua_pushlightuserdata( L, Process32First );
lua_pushcclosure( L, process_iter, 2 );
return 1;
}
Just push the address of the function to call as another upvalue of your closure (lua_pushlightuserdata) then update it on the first call.
Or change your userdata to a structure which contains a handle and the function pointer, and update the function pointer on your first call.
Response to PaulH's edit:
static int process_iter( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
typedef BOOL (WINAPI *PFN_ProcessIter )( HANDLE, LPPROCESSENTRY32 );
PFN_ProcessIter next = ( PFN_ProcessIter )lua_touserdata( L, lua_upvalueindex( 2 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
if (next == Process32First)
{
lua_pushlightuserdata(L, Process32Next);
lua_replace(L, lua_upvalueindex(2));
}
return 1;
}
return 0;
}
Note that I'm using a C++ compiler ( hence, the cast on the calloc function calls) to do this, but the code is essentially C.
Basically, I have a typedef to an unsigned char known as viByte, which I'm using to create a string buffer to parse a file from binary (a TGA file, to be exact - but, that's irrelevant).
I'm writing basic functions for it right now; append, prepend, new, etc.
The problem is that, on the first iteration of the first loop in viByteBuf_Prepend, I get a segmentation fault. I need to know why, exactly, as this is something which could keep me up all night without some pointers (pun intended).
I also would like to know if my algorithms are correct in terms of how the buffer is pre-pending the viByte string. For example, I have a feeling that using memset too much might be a bad idea, and whether or not my printf format for the unsigned char is correct (I have a feeling it isn't, as nothing is getting output to my console).
Compiling on GCC, Linux.
Ze Code
#ifdef VI_BYTEBUF_DEBUG
void viByteBuf_TestPrepend( void )
{
viByteBuf* buf = viByteBuf_New( 4 );
buf->str = ( viByte* ) 0x1;
printf(" Before viByteBuf_Prepend => %uc ", buf->str);
viByteBuf_Prepend( buf, 3, ( viByte* ) 0x2 );
printf(" After viByteBuf_Prepend => %uc ", buf->str);
}
#endif
viByteBuf* viByteBuf_New( unsigned int len )
{
viByteBuf* buf = ( viByteBuf* ) calloc( sizeof( viByteBuf ), 1 );
const int buflen = len + 1;
buf->str = ( viByte* ) calloc( sizeof( viByte ), buflen );
buf->len = buflen;
buf->str[ buflen ] = '\0';
return buf;
}
void viByteBuf_Prepend( viByteBuf* buf, unsigned int len, viByte* str )
{
unsigned int pos, i;
const unsigned int totallen = buf->len + len;
viByteBuf* tmp = viByteBuf_New( totallen );
viByte* strpos = buf->str;
memset( tmp->str, 0, tmp->len );
int index;
for( i = 0; i < buf->len; ++i )
{
index = ( buf->len - i ) - 1;
*strpos = buf->str[ 0 ];
++strpos;
}
memset( buf->str, 0, buf->len );
printf( "%uc\n", buf->str );
i = totallen;
for ( pos = 0; pos < len; ++pos )
{
tmp->str[ pos ] = str[ pos ];
tmp->str[ i ] = buf->str[ i ];
--i;
}
memset( buf->str, 0, buf->len );
buf->len = tmp->len;
memcpy( buf->str, tmp->str, tmp->len );
viByteBuf_Free( tmp );
//memset( )
//realloc( ( viByteBuf* ) buf, sizeof( viByteBuf ) * tmp->len );
}
Many thank yous.
Update
Sorry, I should have explicitly posted the code where the segmentation fault lies. It is right here:
for( i = 0; i < buf->len; ++i )
{
index = ( buf->len - i ) - 1;
*strpos = buf->str[ 0 ]; //<--segmentation fault.
++strpos;
}
On your code you have buf->str[ buflen ] = '\0';, but you only allocate space for buflen. I think you meant buf->str[ len ] = '\0';.
What do you think about this code? Is it the best way? Any improvement?
Roman.h
#ifndef ROMAN_H
#define ROMAN_H
#include <string>
#include <map>
typedef unsigned long int UL_I;
typedef std::map< std::string, UL_I, std::less< std::string > > Map;
class Roman_Number
{
public:
//Constructor
Roman_Number( std::string );
void Convert_to_decimal();
UL_I get_Decimal() const;
std::string get_Roman() const;
private:
std::string s_roman_number;
UL_I d_number;
Map pairs;
Map pairs_substracting;
//Utilitaries functions
void _validate_();
void _initilize_pairs_()
{
pairs.insert( Map::value_type( "I", 1 ) );
pairs_substracting.insert( Map::value_type ( "IV", 4 ) );
pairs.insert( Map::value_type( "V", 5 ) );
pairs_substracting.insert( Map::value_type( "IX", 9 ) );
pairs.insert( Map::value_type( "X", 10 ) );
pairs_substracting.insert( Map::value_type( "XL", 40 ) );
pairs.insert( Map::value_type( "L", 50 ) );
pairs_substracting.insert( Map::value_type( "XC", 90 ) );
pairs.insert( Map::value_type( "C", 100 ) );
pairs_substracting.insert( Map::value_type( "CD", 400 ) );
pairs.insert( Map::value_type( "D", 500 ) );
pairs_substracting.insert( Map::value_type( "CM", 900 ) );
}
UL_I _recursive_convert( std::string );
};
#endif
Roman.cpp
#include <iostream>
#include "Roman.h"
void Roman_Number::_validate_()
{
std::cout << "Validating" << std::endl;
}
Roman_Number::Roman_Number(std::string r_number )
{
_initilize_pairs_();
s_roman_number = r_number;
d_number = 0;
}
void Roman_Number::Convert_to_decimal()
{
std::string s_aux = s_roman_number;
d_number = _recursive_convert( s_aux );
}
UL_I Roman_Number::_recursive_convert( std::string new_roman )
{
if( new_roman == "" )
return 0;
if( pairs_substracting.find( new_roman.substr( 0 , 2 ) ) != pairs_substracting.end() )
return pairs_substracting[new_roman.substr( 0, 2 )] +
_recursive_convert( new_roman.erase( 0, 2) );
else
return pairs[new_roman.substr( 0, 1 )] + _recursive_convert( new_roman.erase( 0, 1 ) );
}
UL_I Roman_Number::get_Decimal() const
{
return d_number;
}
std::string Roman_Number::get_Roman() const
{
return s_roman_number;
}
main.cpp
#include <iostream>
#include "Roman.h"
int main() {
Roman_Number R_N( "XIL" );
R_N.Convert_to_decimal();
std::cout << R_N.get_Decimal();
return 0;
}
How about this? http://codepad.org/mJ05BldC
#include <stdio.h>
int main( void ) {
const char* s = "MCDXLIV";
int x = 0; // result
int j,m=0; // max used digit
const char* p=s, *q; while(*p) ++p;
for( --p; p>=s; p-- ) for( q="IVXLCDM",j=0; *q; q++,j++ ) if( *p==*q )
x += ((j>=m)?m=j,1:-1) * (1+j%4/2*9) * (1+j/4*99) * (1+j%2*4);
printf( "s=%s x=%i\n", s, x );
}
Given
public static final String romanNums = "IVXLCDM";
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String input = console.nextLine();
int arabInt = 0;
for (int i = 0; i < romanNums.length(); i++) {
for (int j = 0; j < input.length(); j++) {
if (input.substring(j, j + 1).equals(romanNums.substring(i, i + 1))) {
arabInt += convertRomToNum(i);
if (j > 0 && romanNums.indexOf(input.substring(j, j + 1)) > romanNums.indexOf(input.substring(j - 1, j))) {
arabInt -= 2 * convertRomToNum(romanNums.indexOf(input.substring(j - 1, j)));
}
}
}
// AFTER OBSERVING PATTERN: 1, 5, 10, 50, 100, 500, 1000; AND ASSOCIATING INDEXES
// OF EACH ROMAN LETTER WITH CORRESPONDING NUMBER IN SEQUENCE ABOVE
public static int convertRomToNum(int i) {
int numBehindLetter = (int) (Math.pow(2, Math.floor(i / 2)) * Math.pow(5, Math.ceil(i / 2.)));
return numBehindLetter;
}
1 = 5^0 * 2^0; 5 = 5^1*2^0; 10 = 5^1*2^0; 50 = 5^2*2^1; 100 = 5^2*2^2; 500 = 5^3*2^2; 1000 = 5^3*2^3 and so on. This is why I have used 'floor' and 'ceil' functions.
Somewhere between convoluted and readable ...
int convRomanToInt(string roman) {
char[] symbol = { 'M', 'D', 'C', 'L', 'X','V','I' };
int[] weight = { 1000, 500, 100, 50, 10, 5 , 1 };
int res = 0, rom = 0, num = 0;
while (rom < roman.Length){
if (roman[rom] == symbol[num]){
res += weight[num];
rom++;
} else if (rom < roman.Length-1 && roman[rom+1] == symbol[num]){
res -= weight[(num&~1)+2];
rom++;
} else {
num++;
}
}
return res;
}