Thread: What can I do in c++, that I can't do in c?

  1. #46
    Registered User Bogdokhan's Avatar
    Join Date
    Jan 2016
    Location
    Belgium
    Posts
    8
    Probably the wrong place to write this but... if you're a mathematician and are looking for some language with a "mathematical flavor" why don't you try functionnal languages like ms-F# or, more logically, Haskel ?

  2. #47
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I'm confident the OP is referring to scientific math when they say "mathematical". Fortran, C and C++ are all fantastic choices for such a domain. I think Haskell was meant for more general programming despite the fact that it's an application of category theory/typed lambda calculus.

    Granted, I think the only kind of useful math is scientific in nature. For some people though, it really does make more sense to think of everything in categorical terms but those people are largely few and far between, I've found. Though I do have a lot of fun in the C++ slack talking about how to make an applicative interface work for std:ptional

  3. #48
    Nasal Demon Xupicor's Avatar
    Join Date
    Sep 2010
    Location
    Poland
    Posts
    179
    MutantJohn, the code you're going to post - are you making a new topic specifically for that? I mean, I'm of two minds about it being offtopic here. Obviously it's to show OP a code sample that's relevant, but then again if we'd continue talking about your code more here it would pretty much be hijacking the thread, right?

    I'd propose that you post a relevant code sample (how C++ facilities let you use your stuff) here and make a new topic about your code specifically where we can ogle at both its usage and implementation, and comment specifically about it more, without hijacking this thread. If it's bigger code base - maybe post a link to github? : )

    Then again, I'm probably being a premature something something here.

  4. #49
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Nah, I'll just post it here because I think it makes the most sense to do so. I'm going to preface this by saying, my abstractions were largely created for my use for my specific needs. I call it a "library" because it's a set of reusable components but I haven't felt a strong obligation to abstract it away from the main project.

    I make meshes. So I need to represent tetrahedra. To do that, I need vertices and I need functions that operate on a set of vertices. One of the cool things I think I did with C++ was how I templated the point structure. I need a convenient way of representing a Cartesian triple. I also want to avoid global typedefs if I want to switch between float, double and maybe someday long double.

    I wound up with this:
    Code:
    template <
      typename T,
      typename = std::enable_if_t<std::is_floating_point<T>::value>>
    struct point_type 
    {
      using type = T;
    };
    
    
    template <>
    struct point_type<float>
    {
      using type = float3;
      constexpr float static const max_coord_value = FLT_MAX;
    };
    
    
    template <>
    struct point_type<double>
    {
      using type = double3;
      constexpr double static const max_coord_value = DBL_MAX;
    };
    
    
    template <typename T>
    using point_t = typename point_type<T>::type;
    I had forgotten that I included max coordinate values but CUDA has some pretty nifty aligned POD types. float3 and double3 both have members x, y and z. This allows me to easily mix up point types in a somewhat readable way. I also don't lose any performance for this abstraction which is good.

    I've also implemented a light matrix class. This is one part where I definitely know my abstraction is lacking. You declare the matrix as `matrix<float, row_value, col_value` but you have to access it yourself manually using 2d-as-1d array conventions, if that's the right way of saying it. Basically, you need to do: `m[row_idx * num_cols + col_idx]` manually.

    This is for a couple of reasons, I'm internally using a 1d array for storage anyway because it's a nice contiguous chunk that I can access rapidly. I was nervous that an intermediate object would incur some overhead to create the 2d access pattern. And for some reason, a method didn't really seem attractive or natural. I have a horribly outdated test file that kind of shows the matrix class was meant to work. There's also some old pivoting stuff in there that I need to take out.

    My code technically only needs to implement a 5x5 matrix at the most so when it came time to implement the determinant, I just brute force-implemented it using some template specializations:
    Code:
    template <typename T>
    __host__ __device__
    auto det(matrix<T, 2, 2> const& m) -> T
    {
      return m.data[0] * m.data[3] - m.data[1] * m.data[2];
    }
    
    
    template <typename T>
    __host__ __device__
    auto det(matrix<T, 3, 3> const& m) -> T
    {
      array<T, 9> const& d = m.data;
      return (
        d[0] * d[4] * d[8] +
        d[1] * d[5] * d[6] +
        d[2] * d[3] * d[7] -
        d[2] * d[4] * d[6] -
        d[1] * d[3] * d[8] -
        d[0] * d[5] * d[7]);
    }
    
    // atrocious performance
    // is literally O(n!) where n is
    // matrix rank
    template <typename T, int N>
    __host__ __device__
    auto det(matrix<T, N, N> const& m) -> T
    {  
      array<T, N * N> const& d = m.data;
      matrix<T, N - 1, N - 1> buff{ 0 };
      T det_value{ 0 };
      
      for (int col = 0; col < N; ++col) {
        
        int buff_size = 0;
        for (int i = 1; i < N; ++i) {
          for (int j = 0; j < N; ++j) {
            if (j == col)
              continue;
            
            buff[buff_size] = d[i * N + j];
            ++buff_size;
          }
        }
        
        T const det_term = d[col] * det(buff);
        
        det_value += (col % 2 == 0 ? det_term : -det_term);
      }
      
      return det_value;
    }
    So, I'm skipping a lot of details and ideas about the core algorithm but I don't want to bog this post down with all that. The point is, C++ makes it easy to write constrained yet generic code and operator and function overloading can allow you to write abstractions that map to something like you'd actually write. It makes sense to multiply matrix A and B with A * B. Same for vectors. It makes sense to add two points p and q with p + q.

    I can also make writing routines to take the orientation of a tetrahedron (basically, is d above or below the plane abc spanned by tetrahedron abcd) and calculate if a point p is inside the circumsphere drawn by tetrahedron abcd with something like:
    Code:
    // another built-in CUDA type, is exactly 4 ints and has members x, y, z and w
    using tetra = int4;
    
    
    enum class orientation { positive = 1, zero = 0, negative = 2 };
    
    
    // Routine that calculates whether the point d
    // is above the triangle spanned by abc
    template <typename T>
    __host__ __device__
    auto orient(
      point_t<T> const& a,
      point_t<T> const& b,
      point_t<T> const& c,
      point_t<T> const& d)
    -> orientation
    { 
      matrix<T, 4, 4> const m{ 1, a.x, a.y, a.z,
                               1, b.x, b.y, b.z,
                               1, c.x, c.y, c.z,
                               1, d.x, d.y, d.z };
    
    
      T const det_value = det<T, 4>(m);
      auto const not_equal_to_zero = !eq<T>(det_value, 0.0);
      
      if (det_value > 0.0 && not_equal_to_zero) {
        return orientation::positive;
        
      } else if (!not_equal_to_zero) {
        return orientation::zero;
        
      } else {
        return orientation::negative;
      }
    }
    
    
    // Calculate the magnitude of a point (i.e. vector)
    template <typename T>
    __host__ __device__
    auto mag(point_t<T> const& p) -> T
    {
      return (
        p.x * p.x +
        p.y * p.y +
        p.z * p.z);
    }
    
    
    // Function that calculates whether or not p is contained
    // in the sphere circumscribed by the tetrahedron abcd
    template <typename T>
    __host__ __device__
    auto insphere(
      point_t<T> const& a,
      point_t<T> const& b,
      point_t<T> const& c,
      point_t<T> const& d,
      point_t<T> const& p)
    -> orientation
    {
      matrix<T, 5, 5> const m{
        1.0, a.x, a.y, a.z, mag<T>(a),
        1.0, b.x, b.y, b.z, mag<T>(b),
        1.0, c.x, c.y, c.z, mag<T>(c),
        1.0, d.x, d.y, d.z, mag<T>(d),
        1.0, p.x, p.y, p.z, mag<T>(p) };
        
      auto const det_value = det<T, 5>(m);
      auto const not_equal_to_zero = !eq<T>(det_value, 0.0);
      
      if (det_value > 0.0 && not_equal_to_zero) {
        return orientation::positive;
        
      } else if (!not_equal_to_zero) {
        return orientation::zero;
        
      } else {
        return orientation::negative;
      } 
    }
    Not like I claim this is "good" code by any means. But it does the job for now. I also have no idea how to handle floating points numbers. I've been very fortunate so far, all I've tested is nice integral Cartesian grids for triangulation. My code doesn't have any divisions in it so the arithmetic is exact because the tested domain size will be smaller than most GPUs will allow. There's now 8 GB GPUs so I'm actually really happy templates make it possible to easily switch between smaller and larger datatypes.

    CUDA also has their version of the STL because it requires it, unfortunately. It's worth it though because Thrust is basically Boost but probably smaller. This entire directory is basically just a bunch of Thrust calls. But Thrust allows me to do things like operate on zip_iterators and higher-order functions allow me write parallel-friendly code.

    This one was actually created with the help from the Nvidia forum. Basically, I represent point and tetrahedron associations as a series of aligned arrays. Basically, pa and ta = point association and tetrahedron association which translates into, point pa[idx] is inside or on tetrahedron ta[idx]. We represent the locational relationship with a bit-encoded integer stored in the array la for location association. I decided that when updating associations, it'd be easiest to do stupid offset calculations where dead indices have the value -1. I can partition all 3 arrays at once and get the new size from a Thrust call. Doing this in pure CUDA C would've basically been a nightmare.
    Last edited by MutantJohn; 10-17-2016 at 10:27 PM.

  5. #50
    CIS and business major
    Join Date
    Aug 2002
    Posts
    287
    As an update, I will probably learn more languages than just c. After studying c for a week, it seems it won't take me longer than a few months to learn all of c's syntax, hence I should probably move onto other languages so I can write more versatile programs.

  6. #51
    Its hard... But im here swgh's Avatar
    Join Date
    Apr 2005
    Location
    England
    Posts
    1,688
    Quote Originally Posted by Terrance View Post
    As an update, I will probably learn more languages than just c. After studying c for a week, it seems it won't take me longer than a few months to learn all of c's syntax, hence I should probably move onto other languages so I can write more versatile programs.
    Depends what you really want to do. Yes there is no such thing as having to many
    tools in the toolbox, but you do not want to bog yourself down with language syntax
    of languages X, Y Z, A, B, C. If you focus on one primary area - be it application scientific
    development or video game development, focus hardcore on the primary languages that
    influence these divisions.

    There is no point learning HTML if you are never going to touch the Internet side of application
    development for example. Languages that are "native" to others such as C, C++, C# and Java
    are probably easier to understand and remember their base differences.

    I know ADA very well, but TBH I have found nearly no need to use it in my current employment.
    That does not mean it has no use - it certainly does have a use in a set limit of fields. But the
    fields they intersect with is not what I wanted to do.
    Double Helix STL

  7. #52
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Also, has anyone mentioned threads yet? Literally, I dropped C and picked up C++ when I wanted to start writing multithreaded code.

  8. #53
    CIS and business major
    Join Date
    Aug 2002
    Posts
    287
    I changed my mind again. I'm sticking with just c. I want to use a highly flexible language, that allows me to write code at a low level, and c is definately the best language for me based around my background. I just read c++ faqs, and c++ has much more features than what I need in a programming language. I want to write in a language where I'll write intellectually challenging algorithms, rather than memorizing a lot of features (which c++ would require me to learn a lot of features, that I wouldn't use in the near future). So I am sticking with c for now.

  9. #54
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    That's like... hey, I'm not going to use an electric screw driver, because y'know, I actually have to put some more effort into learning how to use it. I'm stickin' with the regulator screw driver because I'm familiar with it.

    While C++ may have a bigger toolbox, it also has a lot more useful features, while still staying close to the hardware. You can do some optimizations in C++ that makes some functions free, whereas in C, those may just cost you time (e.g. passing a function pointer in C vs passing a functor in C++). Just to hit it home: games require really low-level access code because they need to ink out every last bit of drop from the hardware, and yet, they don't use C. No, they use C++. I wonder why.

    Anyway, it's your choice. I just think it's a short-sighted and lazy one. But whatever. The important thing is that you go out there and do it and have fun!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #55
    Its hard... But im here swgh's Avatar
    Join Date
    Apr 2005
    Location
    England
    Posts
    1,688
    Quote Originally Posted by Elysia View Post
    Just to hit it home: games require really low-level access code because they need to ink out every last bit of drop from the hardware, and yet, they don't use C. No, they use C++. I wonder why.
    True but it's mainly for the updated features that C++ brings to the table such as OOP, inheritance and polymorphism etc. C was used for years before C++ was - but to be fair, AAA game companies are very slow to adopt to change. Hence why all high profile games will be C++ for many years to come. That being said, only the Engine is built around C++ while the game logic is mainly script.
    Double Helix STL

  11. #56
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Yeah I've seen Johnathan Blow talk about how to code games on stream and it's just not the kind of C++ that would make Elysia proud. They use raw pointers.

  12. #57
    CIS and business major
    Join Date
    Aug 2002
    Posts
    287
    Quote Originally Posted by Elysia View Post
    That's like... hey, I'm not going to use an electric screw driver, because y'know, I actually have to put some more effort into learning how to use it. I'm stickin' with the regulator screw driver because I'm familiar with it.

    While C++ may have a bigger toolbox, it also has a lot more useful features, while still staying close to the hardware. You can do some optimizations in C++ that makes some functions free, whereas in C, those may just cost you time (e.g. passing a function pointer in C vs passing a functor in C++). Just to hit it home: games require really low-level access code because they need to ink out every last bit of drop from the hardware, and yet, they don't use C. No, they use C++. I wonder why.

    Anyway, it's your choice. I just think it's a short-sighted and lazy one. But whatever. The important thing is that you go out there and do it and have fun!

    My learning style is such that I like to learn and relearn a single subject that I'm comfortable with. I had learned c++ many years ago, well over a decade ago, so it's not that I'm incapable of learning it. But I actually have a learning disability, so my learning style requires me to focus on a single subject, until I can gain mastery of the subject.

    I plan on reading the Kernighan and Ritchie C Programming Language book many times, until I have mastered the theoretical underpinnings of the book.
    Last edited by Terrance; 10-22-2016 at 05:15 PM.

  13. #58
    CIS and business major
    Join Date
    Aug 2002
    Posts
    287
    Quote Originally Posted by Terrance View Post
    My learning style is such that I like to learn and relearn a single subject that I'm comfortable with. I had learned c++ many years ago, well over a decade ago, so it's not that I'm incapable of learning it. But I actually have a learning disability, so my learning style requires me to focus on a single subject, until I can gain mastery of the subject.

    I plan on reading the Kernighan and Ritchie C Programming Language book many times, until I have mastered the theoretical underpinnings of the book.
    Or for my personal learning style and abilities, c > c++, so for me, c++ is more like c--

  14. #59
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by whiteflags View Post
    Yeah I've seen Johnathan Blow talk about how to code games on stream and it's just not the kind of C++ that would make Elysia proud. They use raw pointers.
    I've seen what they do. Oh, but I have seen how they write their code. They are partly at fault, and the standard library/language is also partly at fault here.

    Quote Originally Posted by Terrance View Post
    My learning style is such that I like to learn and relearn a single subject that I'm comfortable with. I had learned c++ many years ago, well over a decade ago, so it's not that I'm incapable of learning it. But I actually have a learning disability, so my learning style requires me to focus on a single subject, until I can gain mastery of the subject.

    I plan on reading the Kernighan and Ritchie C Programming Language book many times, until I have mastered the theoretical underpinnings of the book.
    Just so you know, if you plan on learning C and then C++, you're going to have to unlearn a lot of concepts from C if you're going to master C++. Or at least learn to NOT use those concepts from C in C++. Fair warning.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #60
    CIS and business major
    Join Date
    Aug 2002
    Posts
    287
    Or to put my c studying strategy into code language:

    While myCskills != myMaxCSkills
    ++studyC;

    If myCskills == myMaxCSkills
    Break;

    Or in other words I think there is a lot of value in mastering the theory of a subject, and c is low level, and can perform a lot of programming tasks. C# and java are too commercially oriented, in other words, they were designed for businesses to use for profit. C++ has a lot of syntax I find unnecessary at the moment, but are helpful for professional programmers to build large projects, but I'm not building large projects yet, so I want to learn programming at the ground level, which is why I'm choosing c. Also, for work, I use mostly SQL, and I would have have no need for c++ or c# knowledge. But learning the essential components of c does make me a better sql programmer.

Popular pages Recent additions subscribe to a feed

Tags for this Thread