Related posts with WP_Query

parent is your answer here. Every term have a parent value set in its parent property. This value is an integer value, and represent the term id of its parent term. All top level terms have a value of 0 which just simply means it is a top level term

First we need to build an array with parent terms and the specific terms from get_the_category. We will skip 0 values. Once we have our array of ids, we will get all unique values and pass the array of ids to a tax_query in order to save on multiple queries

(The following code is untested and require PHP 5.4+)

function get_related_category_posts()
{
    // Check if we are on a single page, if not, return false
    if ( !is_single() )
        return false;

    // Get the current post id
    $post_id = get_queried_object_id();

    // Get the post categories
    $categories = get_the_category( $post_id );

    // Lets build our array
    // If we don't have categories, bail
    if ( !$categories )
        return false;

    foreach ( $categories as $category ) {
        if ( $category->parent == 0 ) {
            $term_ids[] = $category->term_id;
        } else {
            $term_ids[] = $category->parent;
            $term_ids[] = $category->term_id;
        }
    }

    // Remove duplicate values from the array
    $unique_array = array_unique( $term_ids );

    // Lets build our query
    $args = [
        'post__not_in' => [$post_id],
        'posts_per_page' => 3, // Note: showposts is depreciated in favor of posts_per_page
        'ignore_sticky_posts' => 1, // Note: caller_get_posts is depreciated
        'orderby' => 'title',
        'no_found_rows' => true, // Skip pagination, makes the query faster
        'tax_query' => [
            [
                'taxonomy' => 'category',
                'terms' => $unique_array,
                'include_children' => false,
            ],
        ],
    ];
    $q = new WP_Query( $args );
    return $q;
}

You can then use the code as follows in your single post page

$q = get_related_category_posts();
if ( $q->have_posts() ) {
    while ( $q->have_posts() ) {
    $q->the_post();

        // Your loop

    }
    wp_reset_postdata();
}